贪吃的大嘴 多重背包 dp

    科技2022-07-10  144

    7-4 贪吃的大嘴 (15分) 有一只特别贪吃的大嘴,她很喜欢吃一种小蛋糕,而每一个小蛋糕有一个美味度,而大嘴是很傲娇的,一定要吃美味度和刚好为m的小蛋糕,而且大嘴还特别懒,她希望通过吃数量最少的小蛋糕达到这个目的.所以她希望你能设计一个程序帮她决定要吃哪些小蛋糕.

    输入格式: 先输入一行包含2个整数m、n,表示大嘴需要吃美味度和为m的小蛋糕,而小蛋糕一共有n种,下面输入n行,每行2个整数,第一个表示该种小蛋糕的美味度,第二个表示蛋糕店中该种小蛋糕的总数

    输出格式: 输出一行包含一个整数表示大嘴最少需要吃的小蛋糕数量,若大嘴无法通过吃小蛋糕达到m的美味度和,则输出"><“.

    输入样例: 在这里给出一组输入。例如:

    10 2 4 1 2 10 输出样例: 在这里给出相应的输出。例如:

    4 输入样例: 在这里给出一组输入。例如:

    10 2 4 1 7 3 输出样例: 在这里给出相应的输出。例如:

    <

    题解:这是一个多重背包的问题。 两种解法 第一种 用dp代表,美味度为i时吃的最少的蛋糕块数量。 那么他的转移方程为 dp[k]=min(dp[k],dp[k-v[i]]+1); 一共有三重循环,分别代表蛋糕的种类数,每种蛋糕的数量以及对应的美味度时吃的最少的蛋糕数。 代码如下:

    #include <bits/stdc++.h> #include <algorithm> #include<iostream> #include <stdio.h> #define INF 0x3f3f3f3f const int maxn=500005; using namespace std; typedef long long ll; int dp[maxn]; int a[maxn]; int v[maxn]; int main(){ int m,n,t,va; cin>>m>>n; memset(dp,INF,sizeof(dp)); for(int i=1;i<=n;i++){ cin>>va>>t; //dp[va]=1; /* for(int k=1;k<=t;k++){ a[s+k]=v; } s+=t;*/ v[i]=va; a[i]=t; } //cout<<s<<endl;; dp[0]=0; for(int i=1;i<=n;i++){ for(int j=1;j<=a[i];j++){ for(int k=m;k>=v[i];k--){ if(k-v[i]>=0){ //dp[i-a[j]*k]=k; dp[k]=min(dp[k],dp[k-v[i]]+1); } //if(k-a[i]==0) //f=1; //cout<<"i="<<k<<"dp[i]="<<dp[k]<<endl; } } } if(dp[m]!=INF) cout<<dp[m]<<endl; else cout<<"><"<<endl; return 0; }

    第二种方法:把这个多重背包转为为一个普通的0-1背包,多重背包是同一类有多个,那么只需要把同类的蛋糕一个个单独拿出来,此时的模型就变成了一个最简单的0-1背包。 代码

    #include <bits/stdc++.h> #include <algorithm> #include<iostream> #include <stdio.h> #define INF 0x3f3f3f3f const int maxn=500005; using namespace std; typedef long long ll; int dp[maxn]; int a[maxn]; int v[maxn]; int main(){ int m,n,t,va; cin>>m>>n; memset(dp,INF,sizeof(dp)); int s=0; for(int i=1;i<=n;i++){ cin>>va>>t; //dp[va]=1; for(int k=1;k<=t;k++){ a[s+k]=va; } s+=t; } //cout<<s<<endl; dp[0]=0; for(int i=1;i<=s;i++){ for(int j=m;j>=a[i];j--){ dp[j]=min(dp[j],dp[j-a[i]]+1); } } if(dp[m]!=INF) cout<<dp[m]<<endl; else cout<<"><"<<endl; return 0; }
    Processed: 0.013, SQL: 8