1.完全背包
NYOJ 311
完全背包
時間限制:
3000 ms | 內存限制:65535 KB
難度:
4
- 描述
-
直接說題意,完全背包定義有N種物品和一個容量為V的背包,每種物品都有無限件可用。第i種物品的體積是c,價值是w。求解將哪些物品裝入背包可使這些物品的體積總和不超過背包容量,且價值總和最大。本題要求是背包恰好裝滿背包時,求出最大價值總和是多少。如果不能恰好裝滿背包,輸出NO
- 輸入
-
第一行: N 表示有多少組測試數據(N<7)。
接下來每組測試數據的第一行有兩個整數M,V。 M表示物品種類的數目,V表示背包的總容量。(0<M<=2000,0<V<=50000)
接下來的M行每行有兩個整數c,w分別表示每種物品的重量和價值(0<c<100000,0<w<100000) - 輸出
- 對應每組測試數據輸出結果(如果能恰好裝滿背包,輸出裝滿背包時背包內物品的最大價值總和。 如果不能恰好裝滿背包,輸出NO)
- 樣例輸入
-
2 1 5 2 2 2 5 2 2 5 1
- 樣例輸出
-
NO 1
1 /* 2 雖然感覺這個題目好像要用long long ,才能過,但實際上用int就行,而且long long會超時 3 */ 4 #define N 2008 5 #include<iostream> 6 using namespace std; 7 #include<cstdio> 8 #include<cstring> 9 #define V 50008 10 typedef long long ll; 11 int f[V],val[N]; 12 int T,m,v,w[N]; 13 int main() 14 { 15 scanf("%d",&T); 16 while(T--) 17 { 18 scanf("%d%d",&m,&v); 19 for(int i=1;i<=m;++i) 20 scanf("%d%I64d",&w[i],&val[i]); 21 memset(f,-127,sizeof(f)); 22 f[0]=0; 23 for(int i=1;i<=m;++i) 24 for(int j=w[i];j<=v;++j) 25 f[j]=max(f[j],f[j-w[i]]+val[i]); 26 if(f[v]>0)printf("%I64d",f[v]); 27 else printf("NO\n"); 28 } 29 return 0; 30 }
2.多重背包
Time Limit: 1000MS | Memory Limit: 32768KB | 64bit IO Format: %I64d & %I64u |
Description
Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
Input
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.
Output
For each test case output the answer on a single line.
Sample Input
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
Sample Output
8 4
Source
超時代碼:
1 /*可以看出直接枚舉物品件數和二進制拆分后01背包都不是很快,最快的方法是在DP里面用二進制拆分最快*/ 2 /*------------------------超時代碼---------------------------------------------*/ 3 #define N 100010 4 #include<iostream> 5 using namespace std; 6 #include<cstdio> 7 #include<cstring> 8 #include<vector> 9 int n,m,a[101],c[101]; 10 bool f[N]; 11 int main() 12 { 13 /*vector<int>wu; 14 while(scanf("%d%d",&n,&m)==2) 15 { 16 if(n==0&&m==0) break; 17 memset(f,false,sizeof(f)); 18 clac=0; 19 memset(a,0,sizeof(a)); 20 memset(c,0,sizeof(c)); 21 f[0]=true; 22 wu.clear(); 23 for(int i=1;i<=n;++i) 24 scanf("%d",&a[i]); 25 for(int i=1;i<=n;++i) 26 scanf("%d",&c[i]); 27 for(int i=1;i<=n;++i) 28 { 29 for(int ki=1;ki<=c[i];ki<=1) 30 { 31 clac++; 32 wu.push_back(ki*a[i]); 33 c[i]-=ki; 34 } 35 if(c[i]) 36 { 37 clac++; 38 wu.push_back(c[i]*a[i]); 39 c[i]=0; 40 } 41 } 42 for(int i=0;i<clac;++i) 43 for(int j=m;j>=wu[i];--j) 44 f[j]=f[j]||f[j-wu[i]]; 45 int ret=0; 46 for(int i=1;i<=m;++i) 47 if(f[i]) ret++; 48 printf("%d\n",ret); 49 }*/ 50 while(scanf("%d%d",&n,&m)==2) 51 { 52 if(n==0&&m==0) break; 53 memset(f,false,sizeof(f)); 54 f[0]=true; 55 for(int i=1;i<=n;++i) scanf("%d",&a[i]); 56 for(int i=1;i<=n;++i) scanf("%d",&c[i]); 57 for(int i=1;i<=n;++i) 58 for(int j=1;j<=c[i];++j) 59 for(int k=m;k>=1;--k) 60 if(k>=a[i]) f[k]=f[k]||f[k-a[i]]; 61 int ret=0; 62 for(int i=1;i<=m;++i) 63 if(f[i])ret++; 64 printf("%d\n",ret); 65 } 66 return 0; 67 }
1 /*不知道為什么這個也一直超時*/ 2 #define N 100010 3 #include<iostream> 4 using namespace std; 5 #include<cstring> 6 #include<cstdio> 7 int n,m,a[101],c[101]; 8 int f[N]; 9 int main() 10 { 11 while(scanf("%d%d",&n,&m)==2) 12 { 13 if(n==0&&m==0) break; 14 memset(f,0,sizeof(f)); 15 f[0]=1; 16 for(int i=1;i<=n;++i) 17 scanf("%d",&a[i]); 18 for(int i=1;i<=n;++i) 19 scanf("%d",&c[i]); 20 for(int i=1;i<=n;++i) 21 { 22 for(int ki=1;ki<=c[i];ki<=1) 23 { 24 for(int j=m;j>=ki*a[i];--j)/*相當於更新過程了*/ 25 f[j]+=f[j-ki*a[i]]; 26 c[i]-=ki; 27 } 28 if(c[i]) 29 { 30 for(int j=m;j>=c[i]*a[i];--j) 31 f[j]+=f[j-a[i]*c[i]]; 32 } 33 } 34 int ret=0; 35 for(int i=1;i<=m;++i) 36 if(f[i]) ret++; 37 printf("%d\n",ret); 38 } 39 return 0; 40 }
1 /*網上的AC代碼*/ 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 int f[100005]; 7 int p[105],c[105]; 8 int main() 9 { 10 int i,j,k,n,m,cnt; 11 while(scanf("%d%d",&n,&m)!=EOF) 12 { 13 if(n==0&&m==0) break; 14 for(i=0;i<n;i++) 15 scanf("%d",&p[i]); 16 for(i=0;i<n;i++) 17 scanf("%d",&c[i]); 18 memset(f,0,sizeof(f)); 19 f[0]=1; 20 for(i=0;i<n;i++) 21 { 22 cnt=c[i]; 23 for(k=1;k<=cnt;k<<=1) 24 { 25 for(j=m;j>=k*p[i];j--) 26 f[j]+=f[j-k*p[i]]; 27 cnt-=k; 28 } 29 if(cnt) 30 for(j=m;j>=cnt*p[i];j--) f[j]+=f[j-cnt*p[i]]; 31 } 32 int sum=0; 33 for(i=1;i<=m;i++) 34 if(f[i]) sum++; 35 printf("%d\n",sum); 36 } 37 return 0; 38 }