化工厂装箱员 洛谷 p2530
题目描述
118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品(如果把剩下的全部取出不足10个,则全部取出),如果所有的成品都装进了箱子,那么grant的任务就完成了。
由于装箱是件非常累的事情,grant希望他能够以最少的装箱次数来完成他的任务,现在他请你编个程序帮助他。
输入输出格式
输入格式:
第1行为n(1<=n<=100),为成品的数量
以后n行,每行为一个大写字母A,B或C,表示成品的纯度。
输出格式:
仅一行,为grant需要的最少的装箱次数。
输入输出样例
输入样例#1:
11 A B C A B C A B C A B
输出样例#1:
3
用数组表示所有的状态,状态为当前拿到了第几个物品,同时现在手里有A类物品,B类物品,C类物品各几个,所以每次转移都是把一种东西放进去之后再取几件,然后就比较好写了
上代码:
1 #include<iostream>
2 #include<cstdio>
3 using namespace std;
4 int n,w[105],f[105][15][15][15],t[4],ans;
5 int read(){//read函数是对字符进行一下转变,变成数字
6 int x;char c=getchar();
7 while(c<'A'||c>'C') c=getchar();
8 x=c-'A'+1;
9 return x;
10 }
11
12 void dp(int cur,int nxt,int a,int b,int c,int k){//cur是当前状态的物品数,nxt转移后的状态的物品数,abc是三种物品在手中的数量,k是要放哪一种物品
13 int aa=a,bb=b,cc=c;
14 nxt=min(nxt,n);//不能超出
15 if(k==1) aa=0;
16 else if(k==2) bb=0;
17 else if(k==3) cc=0;
18 for(int i=cur+1;i<=nxt;i++){
19 if(w[i]==1) aa++;
20 else if(w[i]==2) bb++;
21 else if(w[i]==3) cc++;
22 }
23 f[nxt][aa][bb][cc]=min(f[nxt][aa][bb][cc],f[cur][a][b][c]+1);//上一个状态的次数再多放一次
24 }
25
26 int main(){
27 scanf("%d",&n);
28 for(int i=1;i<=n;i++){
29 w[i]=read();
30 if(i<=10){
31 t[w[i]]++;//先记录前十个物品三种各有几个
32 }
33 }
34 if(n<=10){//小于十个就直接输出
35 for(int i=1;i<=3;i++){
36 ans+=(t[i]>0?1:0);
37 }
38 printf("%d\n",ans);
39 return 0;
40 }
41
42 for(int i=0;i<=n;i++){
43 for(int j=0;j<=10;j++){
44 for(int k=0;k<=10;k++){
45 for(int l=0;l<=10;l++){
46 f[i][j][k][l]=(1<<30);//初始化
47 }
48 }
49 }
50 }
51 f[10][t[1]][t[2]][t[3]]=0;//初状态为零次, i<=10&&j<=t[1]&&k<=t[2]&&l<=t[3] 的状态不变为零,因为这些状态一定不是最优,所以不必初始化
52 for(int i=10;i<=n;i++){
53 for(int j=0;j<=10;j++){
54 for(int k=0;k<=10;k++){
55 for(int l=0;l<=10;l++){
56 if(f[i][j][k][l]!=(1<<30)){//如果这个状态可以转移
57 if(j>0){
58 dp(i,i+j,j,k,l,1);//分别尝把每一种物品放回去进行状态进行转移
59 }
60 if(k>0){
61 dp(i,i+k,j,k,l,2);
62 }
63 if(l>0){
64 dp(i,i+l,j,k,l,3);
65 }
66 }
67 }
68 }
69 }
70 }
71 ans=(1<<30);
72 for(int j=0;j<=10;j++){
73 for(int k=0;k<=10;k++){
74 for(int l=0;l<=10;l++){
75 ans=min(ans,f[n][j][k][l]+(j>0?1:0)+(k>0?1:0)+(l>0?1:0));//在所有已经取了n个物品的状态里取最小值
76 }
77 }
78 }
79 printf("%d\n",ans);
80 return 0;
81 }