【codevs2098】【Tyvj1625】化工厂装箱员,煞笔的人打煞笔的DP

来源:互联网 发布:agile plm java被停止 编辑:程序博客网 时间:2024/05/17 09:34

传送门1
传送门2
写在前面:数据结构题写多了,写dp反而不会写了
思路:刚开始以为是贪心,很快发现这是错误的233(反例很好找的),后来看到n才100,就动了一些歪脑筋打暴力,后来才发现是一个可以记忆化搜索的DP,f[i][x][y][z]指流水线上剩余i个产品,手里有x个A,y个B,z个C时所需要的最少装箱次数,显然我们可以以此转移三种状态:装箱A,装箱B,装箱C,同时记忆化搜索除去了很多重复的状态(比如在流水线上一堆C的情况下装2个A,3个B与装3个B, 2个A效果一样)
注意:别打暴搜,注意细节!
代码:

#include<bits/stdc++.h>using namespace std;int n,a[110],f[110][20][20][20];char ch;bool flag[110][20][20][20];int dfs(int remain,int x,int y,int z){    int tot=x+y+z,k=0;    for (int i=n-remain+1;i<=n;i++)    {        if (tot+k==10) break;        if (a[i]==1) x++;        if (a[i]==2) y++;        if (a[i]==3) z++;        k++;    }    if (flag[remain-k][x][y][z]) return f[remain-k][x][y][z];    flag[remain-k][x][y][z]=1;    if (remain-k==0)    {        f[0][x][y][z]=min(f[0][x][y][z],(x>0)+(y>0)+(z>0));//没有剩余的情况下显然装a,b,c的顺序就无所谓了,直接加上就好        return f[0][x][y][z];    }    if (x) f[remain-k][x][y][z]=min(f[remain-k][x][y][z],dfs(remain-k,0,y,z)+1);    if (y) f[remain-k][x][y][z]=min(f[remain-k][x][y][z],dfs(remain-k,x,0,z)+1);    if (z) f[remain-k][x][y][z]=min(f[remain-k][x][y][z],dfs(remain-k,x,y,0)+1);    return f[remain-k][x][y][z];}main(){    scanf("%d",&n);    for (int i=1;i<=n;i++)    {        ch=getchar();        while (ch<'A'||ch>'C') ch=getchar();        a[i]=ch-'A'+1;    }    memset(f,63,sizeof(f));    printf("%d",dfs(n,0,0,0));}
1 0
原创粉丝点击