Codeforces Round #510 (Div. 2)(B)
https://www.cnblogs.com/violet-acmer/p/9682082.html
题意:
如果可以通过喝果汁将维生素A,B,C全部摄取,求最小花费,如果不能,输出"-1"。
题解:
我的思路:每个果汁含有的维生素最多有7种可能,分别为
A B C
AB(BA) AC(CA) BC(CB)
ABC(ACB)(BAC)(BCA)(CAB)(CBA)
将其分别对应为数字1-7
设变量price[i]
price[1] : 只含维生素A的饮料的最小价钱
price[2] : 只含维生素B的饮料的最小价钱
price[3] : 只含维生素C的饮料的最小价钱
...........
price[7] : 只含维生素ABC的饮料的最小价钱,注意含有维生素ACB和其余四种情况都记录在只含维生素ABC里
易知price[ ]记录的是含某维生素的最小花费的饮料的假期那
当n个果汁的信息输入完后,price[ ]数组也初始化完毕。
接着将含有复合(例如含有维生素AB)维生素的price[ ] 与单个维生素的总价格比较,如果复合的更便宜,则不更新,如果单个的总价格更便宜,则更新复合的价格
例如price["AB"]=10,price["A"]=2,price["B"]=6;
显然有price["AB"] > price["A"]+price["B"];
所以更新price["AB"]=price["A"]+price["B"];
最后输出price["ABC"]。
注意不存在三种维生素的情况要输出"-1"。
AC代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<map> 6 using namespace std; 7 #define INF 0x3f3f3f3f 8 const int maxn=1010; 9 10 int n; 11 int price[8]; 12 bool vis[4]; 13 14 map<string,int>mymap; 15 16 void Copy(string &s,char ss[]) 17 { 18 int len=strlen(ss); 19 for(int i=0;i < len;++i) 20 s += ss[i]; 21 s += '\0'; 22 } 23 void Initial() 24 { 25 mymap.clear(); 26 memset(vis,false,sizeof vis); 27 memset(price,INF,sizeof price); 28 mymap["A"]=1; 29 mymap["B"]=2; 30 mymap["C"]=3; 31 mymap["AB"]=mymap["BA"]=4; 32 mymap["AC"]=mymap["CA"]=5; 33 mymap["BC"]=mymap["CB"]=6; 34 mymap["ABC"]=mymap["ACB"]=mymap["BAC"]=mymap["BCA"]=mymap["CAB"]=mymap["CBA"]=7; 35 } 36 void Read() 37 { 38 scanf("%d",&n); 39 for(int i=1;i <= n;++i) 40 { 41 int c; 42 string s; 43 scanf("%d",&c); 44 cin>>s; 45 if(price[mymap[s]] > c) 46 price[mymap[s]]=c; 47 } 48 } 49 void Process() 50 { 51 price[4]=min(price[4],price[1]+price[2]); 52 price[5]=min(price[5],price[1]+price[3]); 53 price[6]=min(price[6],price[2]+price[3]); 54 price[7]=min(price[7],min(min(price[4]+price[3],price[5]+price[2]),price[6]+price[1])); 55 price[7]=min(price[7],min(min(price[4]+price[5],price[4]+price[6]),price[5]+price[6])); 56 printf("%d\n",price[7] >= INF ? -1:price[7]);//通过将所有的price[ ] 值设置为INF来判断ABC是否都存在 57 } 58 int main() 59 { 60 Initial(); 61 Read(); 62 Process(); 63 }
参考大神dp代码%%%%%%%%
将ABC转化成二进制数:
A : 001
B : 010
C : 100
AB=BA=A | B=011
AC=CA=A | C=101
BC=CB=B | C=110
ABC=ACB=BAC=BCA=CAB=CBA=A | B | C =111
定义dp[i][j]
i的范围为[0,n] : 1 ->第1瓶饮料 ,2->第2瓶饮料,........,n->第n瓶饮料
j的范围为[0,7] : 1代表维生素A,2代表维生素B,....,7代表维生素ABC
第 j 列表示“添加上维生素 j 缺少的维生素所需的最少的花费”
例如当j=5,表示当前维生素 j 含有的维生素为AC,缺少维生素B,而维生素B可以从含有维生素B或含有维生素AB或含有维生素BC的饮料中获取,从中选取花费最少的饮料
初始化dp[0][0,1,....6]=INF; F[0,1,....n][7]=0;。
状态转移方程F[i][j]=min(F[i-1][j | Si]+Wi,F[i-1][j]);
Si : 第i瓶饮料含有的维生素
Wi : 第i瓶饮料的花费
dp[i][j] : 第i瓶饮料“添加上维生素 j 缺少的维生素所需的最少的花费”
dp[i-1][j | Si] + Wi : 当前饮料可以为维生素 j 补充维生素Si,还差维生素 (ABC - (j+Si) ),而 (i-1) 行的 ( j | Si ) 列表示的就是添加差的维生素 (ABC - (j+Si) )所需的最小花费
所以dp[i-1][j | Si] + Wi 表示维生素 j 在添加上当前维生素Si所需的最小花费,但dp[i][j]存储的是最小花费,故需要和之前的dp[i-1][ j ]比较一下,谁花费少要谁。
例如:
Input:
3
10 A
15 B
16 C
由状态转移方程生成的二维表格如图所示:
w : 第i瓶饮料的花费
S : 第i瓶饮料所包含的维生素
当i=1时
j=0 : dp[1][0]=min(dp[0][A|0]+10,dp[0][0]) // A | 0 = A = 1
当前 j 不含有任何维生素,缺少维生素ABC,所以需要从之前的饮料中找到含有维生素ABC的饮料,但维生素A是第一瓶饮料,所以在此之前并没有出现含维生素ABC的饮料,所以dp[0][0]=INF;
同理可得j=1,2,3,4,5时dp[0][j]=INF;
当j=6时 : dp[1][6]=min(dp[0][A | BC]+10,dp[0][0])// A | BC = ABC = 7
6代表的是维生素BC,缺少的是维生素A,而当前饮料含有维生素A,j + A后正好为ABC,不缺少维生素,这就是为什么初始化dp[0,....,n][7]=0的原因,
所以dp[1][6]=0+10=10;
当i=2时
j=0 : dp[2][0]=min(dp[1][B | 0]+15,dp[1][0]) // B | 0 = B = 2
同样, j=0时不含有任何维生素,缺少维生素ABC,当前饮料可以提供维生素B,还缺少维生素AC,但之前并未出现含有维生素C的饮料,所以dp[1][B | 0] + 15 = INF+15
而且之前的dp[1][0]=INF,所以dp[2][0]=INF;
同理当j=1,2,3时dp[1][j]=INF
j=4 : dp[2][4]=min(dp[1][B | C]+15,dp[1][4]) // B | C = BC = 6
4代表的是维生素C,缺少维生素AB,而当前饮料含有维生素B,j + B = BC,还缺少维生素A,而dp[1][B | C]= 10 表示的正好是目前添加维生素A所需的最少花费,
所以dp[2][4]=10+15=25;
其余情况参照上述描述;
AC代码如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define INF 0x3f3f3f3f 6 const int maxn=1010; 7 8 struct Juice 9 { 10 int w; 11 char s[4]; 12 int a; 13 }; 14 int n; 15 int dp[maxn][8]; 16 Juice juice[maxn]; 17 18 void Read() 19 { 20 scanf("%d",&n); 21 for(int i=1;i <= n;++i) 22 { 23 scanf("%d%s",&juice[i].w,juice[i].s); 24 int len=strlen(juice[i].s); 25 for(int j=0;j < len;++j) 26 { 27 if(juice[i].s[j] == 'A') 28 juice[i].a |= 1;//A <- 001 29 else if(juice[i].s[j] == 'B') 30 juice[i].a |= 2;//B <- 010 31 else 32 juice[i].a |= 4;//C <- 100 33 } 34 } 35 } 36 void Initial() 37 { 38 for(int i=0;i <= n;++i) 39 dp[i][7]=0; 40 for(int j=0;j < 7;++j) 41 dp[0][j]=INF; 42 } 43 void Process() 44 { 45 Initial(); 46 for(int i=1;i <= n;++i) 47 for(int j=0;j < 7;++j) 48 dp[i][j]=min(dp[i-1][j|juice[i].a]+juice[i].w,dp[i-1][j]); 49 printf("%d\n",dp[n][0] >= INF ? -1:dp[n][0]); 50 } 51 int main() 52 { 53 Read(); 54 Process(); 55 return 0; 56 }