化工厂装箱员 洛谷 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 }

 

 

 

 

posted @ 2017-08-08 16:41  circlegg  阅读(165)  评论(0编辑  收藏  举报