[SHOI2001]化工厂装箱员 题解
作者:互联网
题目描述
118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有 \(3\) 种不同的纯度,\(A\):100%,\(B\):1%,\(C\):0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取 \(10\) 个成品(如果一共不足 \(10\) 个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持 \(10\) 个成品(如果把剩下的全部取出不足 \(10\) 个,则全部取出),如果所有的成品都装进了箱子,那么grant的任务就完成了。
由于装箱是件非常累的事情,grant希望他能够以最少的装箱次数来完成他的任务,现在他请你编个程序帮助他。
输入格式
第 \(1\) 行为\(n\)(\(1 \leq n \leq 100\)),为成品的数量
以后 \(n\)行,每行为一个大写字母 \(A\) ,\(B\) 或 \(C\),表示成品的纯度。
输出格式
仅一行,为grant需要的最少的装箱次数。
样例输入
11
A
B
C
A
B
C
A
B
C
A
B
样例输出
3
发现针对当前处理的状态,三种情况总和不超过十个,考虑暴力维护。
状态 \(dp[i][j][k][t]\) 表示处理到第 \(i\) 个物品时,手里的有 \(A,B,C\) 分别有 \(j,k,t\) 个的情况。
自然有转移:
当第\(i\) 个物品为 \(j\) 时\(dp[i][j][k][t]=dp[i-1][j-1][k][t]\)
当第\(i\) 个物品为 \(k\) 时\(dp[i][j][k][t]=dp[i-1][j][k-1][t]\)
当第\(i\) 个物品为 \(t\) 时\(dp[i][j][k][t]=dp[i-1][j][k][t-1]\)
注意合法情况为转移前已有物品,保持减一后仍大于等于零。
处理把一种货物全部清空,设计状态:
\(dp[i][0][k][t]=min(dp[i][0][k][t],dp[i][j][k][t]+1)\)
同理可得剩下两种状态,不再赘述。
初始化将 \(dp\) 数组设置为 \(+\infty\),\(dp[0][0][0][0]=0\)。
全程保持 $j+t+k \leq 10 $,符合题意。
不必考虑出现物品不够 \(10\) 个时便转移,得出错误答案。
目标状态:\(dp[n][0][0][0]\) ,即所有物品清空,不再剩余时的最大值。
Code.
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int dp[N][11][11][11],opt[N],n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
char a;
scanf("%s",&a);
if(a=='A') opt[i]=1;
else if(a=='B') opt[i]=2;
else opt[i]=3;
}
memset(dp,0x3f,sizeof dp);
dp[0][0][0][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=10;j++)
for(int k=0;k<=10;k++)
for(int t=0;t<=10;t++)
{
if(j+k+t > 10) continue ;
if(opt[i]==1 && j) dp[i][j][k][t]=dp[i-1][j-1][k][t];
if(opt[i]==2 && k) dp[i][j][k][t]=dp[i-1][j][k-1][t];
if(opt[i]==3 && t) dp[i][j][k][t]=dp[i-1][j][k][t-1];
int sum=dp[i][j][k][t]+1;
dp[i][0][k][t]=min(dp[i][0][k][t],sum);
dp[i][j][0][t]=min(dp[i][j][0][t],sum);
dp[i][j][k][0]=min(dp[i][j][k][0],sum);
}
printf("%d",dp[n][0][0][0]);
return 0;
}
标签:10,int,题解,成品,SHOI2001,物品,装箱,dp 来源: https://www.cnblogs.com/EastPorridge/p/16365617.html