EOJ-2144 抗震机械制造
http://acm.cs.ecnu.edu.cn/problem.php?problemid=2144
题意:给出n种物品以及m种材料,每种物品由不同材料制成,每种材料需要一定的资金(付钱后可无限用),求资金不超过给定p的情况下能造出的最多种类物品
题目用二进制的方式表示物品由哪些材料构成,1表示选,0表示不选,使用时转化为十进制,过程以二进制为主。
思路:记下每个物品的材料状态(二进制转化为十进制)(a[i]),在资金不超过限定的条件下,选取包含给出物品材料状态的某种状态。假设某物品的材料状态为1010,则所有包含其状态的情况,都可以制造出该物品(如1110,1111,1011),即如果没有资金限制,11…11则是所有问题的最优解。
dp[i][j]表示选择第i个物品时,选取材料状态为j时最多可以造出的物品数量,j从a[i] ~ 2^m-1 (只有大于等于a[i]的状态可能包含它)
则当j状态是包含第i个物品状态a[i]时,dp[i][j]=dp[i-1][j]+1,(说明选取材料状态为j可制造出第i个物品,即是在取i-1个物品,材料状态为j时的最优解状态下加一),且j状态的资金不超过限定值。(可优化空间)
j包含物品i的状态的表达式为 a[i] & j == a[i] ,例如1010 与1111 位与就是1010则包含, 而与1100位与变为了1000则不是包含。
1 #include<map> 2 #include<set> 3 #include<list> 4 #include<cmath> 5 #include<ctime> 6 #include<queue> 7 #include<stack> 8 #include<cctype> 9 #include<cstdio> 10 #include<string> 11 #include<cstdlib> 12 #include<cstring> 13 #include<iostream> 14 #include<algorithm> 15 using namespace std; 16 int c[20]; //材料资金 17 int getValue(int x){ 18 int sum=0,pos=0; 19 while(x){ 20 sum+=(x%2)*c[pos++]; 21 x>>=1; 22 } 23 return sum; 24 } 25 int main(){ 26 int T; 27 cin>>T; 28 while(T--){ 29 int n,m,p; 30 scanf("%d%d%d",&n,&m,&p); 31 int a[105],dp[(1<<16)+5],k[(1<<16)+5]; //a[]为物品的材料状态,k[]存放每种状态的资金总和 32 for(int i=0;i<m;i++) 33 scanf("%d",c+i); 34 for(int i=0;i<(1<<m);i++) 35 k[i]=getValue(i); 36 for(int i=1;i<=n;i++){ 37 int sum=0; 38 for(int j=0;j<m;j++){ 39 int x; 40 scanf("%d",&x); 41 sum+=pow(2.0,j)*x; 42 } 43 a[i]=sum; //将材料状态存为十进制 44 } 45 memset(dp,0,sizeof(dp)); 46 for(int i=1;i<=n;i++) 47 for(int j=(1<<m)-1;j>=a[i];j--){ 48 if((j&(a[i]))==a[i] && k[j]<=p) //表示j状态包含a[i]状态,且资金不大于限定值 49 dp[j]++; //在材料状态j下可存放第i个物品 50 } 51 int Max=0; 52 for(int i=0;i<=(1<<m)-1;i++) 53 Max=max(Max,dp[i]); //找到最优解(不一定在dp[(1<<m)-1]中,因为受资金限制) 54 printf("%d\n",Max); 55 } 56 return 0; 57 }