用多重背包写总是超时,看了大神的思路。。。
一开始我完全用多重背包,超时。。。
后来一开始用贪心求出最小张数,然后把多重背包转化成01背包和完全背包,再次超时。。。
再然后就是下面的代码了,但是背包比起完全用贪心写还是太慢了。
#include<iostream> #include<stdio.h> #include<math.h> #include<string.h> #include<vector> #include<list> #include<algorithm> using namespace std; #define MAX 1000010 int p; int a[6]; int v[6] = {1,5,10,50,100}; int dpu[MAX]; int conut[MAX]; void MP(int value,int n); void findu(); int findl(); int MIN; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&p); for(int i=0;i<5;i++){ scanf("%d",&a[i]); } if(findl()){ printf("%d ",MIN); /*for(int i=0;i<=p;i++){ dpu[i] = -0x3f3f3f3f; } dpu[0] = 0; for(int i=0;i<5;i++){ MP(v[i],a[i]); }*/ findu(); if(dpu[p]>=0){ printf("%d\n",dpu[p]); } else{ printf("-1\n"); } } else{ printf("-1 -1\n"); } } return 0; } void findu() { int i,j; memset(dpu,-100,4*(p+1)); dpu[0]=0; for(i=0;i<5;i++){ memset(conut,0,4*(p+1)); for(j=v[i];j<=p;j++){ if(dpu[j]<dpu[j-v[i]]+1 && conut[j-v[i]]<a[i]){ dpu[j]=dpu[j-v[i]]+1; conut[j]=conut[j-v[i]]+1; } } } } //先用贪心求出最小张数 int findl(){ int num = 0; int c = p; for(int i=4;i>=0;i--){ int t = c/v[i]; if(t<=a[i]){ num += t; c -= t*v[i]; } else{ num += a[i]; c -= a[i]*v[i]; } if(c==0){ MIN = num; return 1; } } return 0; } //用这种多重背包的写法(转换成01背包和完全背包)会超时 void CP(int value){ for(int i=value;i<=p;i++){ dpu[i] = max(dpu[i],dpu[i-value] + 1); } } void ZOP(int value,int n){ for(int i=p;i>=value;i--){ dpu[i] = max(dpu[i],dpu[i-value] + n); } } void MP(int value,int n){ if(n*value>=p){ CP(value); } else{ int k=1; while(k<=n){ ZOP(value*k,k); n-=k; k*=2; } ZOP(value*n,n); } }