洛谷 P2530 [SHOI2001]化工厂装箱员 题解【DP】【枚举】

作者: wjyyy 分类: DP,枚举,解题报告 发布时间: 2018-07-13 10:59

点击量:146

 

   动态规划的多维枚举。

 

题目描述

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[m][i][j][k]来维护装到第m格,目前手上有i个A,j个B,k个C。那么每次转移可以把i/j/k中的一个变成0,把m加上这个数,并且更新i,j,k在(m,m+i/j/k]这一段新出现的次数。例如选了i,就转移为f[m+i][i’][j+j’][k+k’],i’表示在(m,m+i]这一段中A出现的次数。每次暴力枚举i,j,k有多少个,只要f数组中它不是inf就可以用刷表法转移。

 

   遇到多重状态时一定要多撕烤思考,当范围小时想想高维DP,范围大时也可以高维DP骗分。

 

Code:

#include<cstdio>
#include<cstring>
int min(int x,int y)
{
    return x<y?x:y;
}
int f[110][11][11][11];
int a[110];
int b[110],c[110];
int main()
{
    memset(f,0x3f,sizeof(f));
    int n;
    scanf("%d",&n);
    char s[20];
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        a[i]=a[i-1]+(s[0]=='A');
        b[i]=b[i-1]+(s[0]=='B');
        c[i]=c[i-1]+(s[0]=='C');
    }
    int up=min(10,n);//注意控制手上不到10个的状态
    f[up][a[up]][b[up]][c[up]]=0;
    for(int i=up,flag=0;i<=n&&flag<3;i++)
    {
        for(int A=0;A<=10;A++)
            for(int B=0;B<=10;B++)
                for(int C=0;C<=10;C++)
                    if(f[i][A][B][C]!=0x3f3f3f3f)
                    {
                        int nxt=min(i+A,n);
                        int aa=a[nxt]-a[i];
                        int bb=B+b[nxt]-b[i];
                        int cc=C+c[nxt]-c[i];
                        f[nxt][aa][bb][cc]=min(f[nxt][aa][bb][cc],f[i][A][B][C]+1);//把A装箱
                        nxt=min(i+B,n);
                        aa=A+a[nxt]-a[i];
                        bb=b[nxt]-b[i];
                        cc=C+c[nxt]-c[i];
                        f[nxt][aa][bb][cc]=min(f[nxt][aa][bb][cc],f[i][A][B][C]+1);
                        nxt=min(i+C,n);
                        aa=A+a[nxt]-a[i];
                        bb=B+b[nxt]-b[i];
                        cc=c[nxt]-c[i];
                        f[nxt][aa][bb][cc]=min(f[nxt][aa][bb][cc],f[i][A][B][C]+1);
                    }
        if(i==n)
        {
            flag++;
            i--;
        }
    }
    printf("%d\n",f[n][0][0][0]);
    return 0;
}

 

说点什么

avatar
  Subscribe  
提醒
/* */