洛谷P2530 [SHOI2001]化工厂装箱员

来源:互联网 发布:淘宝老客户回访率查询 编辑:程序博客网 时间:2024/06/09 17:24

题目描述

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


动态规划部分

定义 f[i][A][B][C] 为前i个中 A种有AB种有BC种有C个 所需最小的操作次数

那么每一次操作可以将 目前的A种或B种或C种的物品全部移除

那么 f[i+A][A][B][C] f[i+B][A][B][C] f[i+C][A][B][C](A B C分别代表在i+1 ~ i+(ABC)ABC) 就是我的代码中的 grant函数

均可以由f[i][A][B][C]推得 然后对每一项求得最小操作次数

i=nf[n][A][B][C]=f[n][A][B][C]+A>0+B>0+C>0

再在 f[n][j][k][l]中求最小值即为ans
以下为代码

#include <bits/stdc++.h>using namespace std;const int maxn=105,INF=1<<30-1;int f[maxn][11][11][11],a[maxn],n,p[4],ans=INF;char c;inline int cacl(char c){    if(c=='A')return 1;    else if(c=='B')return 2;    else if(c=='C')return 3;}inline void grant(int x,int y,int A,int B,int C,int k){    int A1=A,B1=B,C1=C;y=min(y,n);    if(k==1)A1=0;else if(k==2)B1=0;else C1=0;//对一种物品进行操作    for(int i=x+1;i<=y;i++){//分别记录A',B',C'的值        if(a[i]==1)A1++;        else if(a[i]==2)B1++;        else if(a[i]==3)C1++;    }    f[y][A1][B1][C1]=min(f[x][A][B][C]+1,f[y][A1][B1][C1]);//找最小的次数达到此状态}inline void inti(){    cin>>n;    for(int i=1;i<=n;i++){        cin>>c;        a[i]=cacl(c);//将字符改为数字 虽然并没起到什么帮助        if(i<=10)p[a[i]]++;//记录数字1 2 3的个数    }    if(n<=10){//在n<=10的时候特判然后对每种颜色均操作一次 否则无法计算    cout<<(int)(p[1]>0)+(int)(p[2]>0)+(int)(p[3]>0)<<endl;    exit(0);}    for(int i=0;i<=n;i++)     for(int j=0;j<=10;j++)      for(int k=0;k<=10;k++)       for(int l=0;l<=10;l++)        f[i][j][k][l]=INF;//数组初始化 均设置为不可到达    f[10][p[1]][p[2]][p[3]]=0;//起点总次数为0}inline void dp(){    for(int i=10;i<=n;i++)     for(int j=0;j<=10;j++)      for(int k=0;k<=10;k++)       for(int l=0;l<=10;l++)       if(f[i][j][k][l]!=INF){//枚举f[i][j][k][l]找到可以推得的状态           if(j)grant(i,i+j,j,k,l,1);//如果A还有剩余则取光A 下同上           if(k)grant(i,i+k,j,k,l,2);           if(l)grant(i,i+l,j,k,l,3);       }    for(int j=0;j<=10;j++)     for(int k=0;k<=10;k++)      for(int l=0;l<=10;l++)       ans=min(ans,f[n][j][k][l]+(int)(j>0)+(int)(k>0)+(int)(l>0));//对于每一个已经没有物品在流水线上的状态 只需每种均操作一次即可}int main(){    inti();//输入    dp();//dp主程序    cout<<ans<<endl;    return 0;}