传送门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));
}