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
",Max);
55     }
56     return 0;
57 }
View Code
原文地址:https://www.cnblogs.com/KimKyeYu/p/3168580.html