bzoj 1806: [Ioi2007]Miners 矿工配餐 动态规划

来源:互联网 发布:itoa函数在linux 编辑:程序博客网 时间:2024/05/14 09:38

题目

传送门

分析

刚看题目还以为是什么网络流之类的玄学算法。

因为计算贡献时只跟煤矿1最后两次到达的食品车和煤矿2最后两次到达的食品车有关,那么我们可以考虑状态压缩。
用两个两位的四进制数分别表示到达煤矿1和煤矿2的最后两辆食品车。
用f[i,j,k]表示分配完第i辆食品车后煤矿1的状态为j,煤矿2的状态为k的最大贡献。
考虑到从后往前转移比较麻烦,我们只要从前往后转移就好了。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define N 100005using namespace std;int n,a[N],vis[4],f[2][20][20];char str[N];int main(){    scanf("%d",&n);    scanf("%s",str+1);    for (int i=1;i<=n;i++)        if (str[i]=='M') a[i]=1;        else if (str[i]=='B') a[i]=2;        else a[i]=3;    int now=0;    f[now][0][0]=1;    for (int i=0;i<n;i++)    {        memset(f[1-now],0,sizeof(f[1-now]));        for (int j=0;j<16;j++)            for (int k=0;k<16;k++)                if (f[now][j][k])                {                    vis[1]=vis[2]=vis[3]=0;                    int w=0;                    if (j%4>0&&!vis[j%4])                    {                        vis[j%4]=1;                        w++;                    }                    if (j/4>0&&!vis[j/4])                    {                        vis[j/4]=1;                        w++;                    }                    if (!vis[a[i+1]])                    {                        vis[a[i+1]]=1;                        w++;                    }                    f[1-now][j%4*4+a[i+1]][k]=max(f[1-now][j%4*4+a[i+1]][k],f[now][j][k]+w);                    vis[1]=vis[2]=vis[3]=w=0;                    if (k%4>0&&!vis[k%4])                    {                        vis[k%4]=1;                        w++;                    }                    if (k/4>0&&!vis[k/4])                    {                        vis[k/4]=1;                        w++;                    }                    if (!vis[a[i+1]])                    {                        vis[a[i+1]]=1;                        w++;                    }                    f[1-now][j][k%4*4+a[i+1]]=max(f[1-now][j][k%4*4+a[i+1]],f[now][j][k]+w);                }        now=1-now;    }    int ans=0;    for (int i=0;i<16;i++)        for (int j=0;j<16;j++)            ans=max(ans,f[now][i][j]);    printf("%d",ans-1);    return 0;}
0 0