题目
Description
118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品(如果把剩下的全部取出不足10个,则全部取出),如果所有的成品都装进了箱子,那么grant的任务就完成了。
由于装箱是件非常累的事情,grant希望他能够以最少的装箱次数来完成他的任务,现在他请你编个程序帮助他。
Input
第1行为n(1<=n<=100),为成品的数量
以后n行,每行为一个大写字母A,B或C,表示成品的纯度。
Output
仅一行,为grant需要的最少的装箱次数。
Sample Input
11 A B C A B C A B C A B
Sample Output
3
思路
这是一道 $ dp$ 题;
我们可以设 $dp[i][j][k][l]$ 表示当取到第 $i$个成品时,手里有$A,B,C$ 种成品各 $j~,k~,l$个;
那么就有两种情况,取成品,和装箱;
那么取走成品的转移方程是:
$if(j& &s[i]=='A')$
$dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j-1][k][l])$
表示取走成品 $A$;
那么装箱的转移方程就是:
$dp[i][0][k][l]=min(dp[i][0][k][l],dp[i][j][k][l]+1)$
表示把成品 $A$ 进行装箱,装箱的次数加$1$;
这样就可以$AC$ 了;
代码
#include<bits/stdc++.h> #define re register typedef long long ll;using namespace std; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n; char s[101]; ll dp[101][11][11][11]; int main() { memset(dp,127/3,sizeof(dp)); n=read();//读入 for(re ll i=1;i<=n;i++) cin>>s[i];//读入 dp[0][0][0][0]=0;//赋初值 for(re ll i=1;i<=n;i++) for(re ll j=0;j<=10;j++) for(re ll k=0;k<=10;k++) for(re ll l=0;l<=10;l++) { if(j+k+l>10) continue;//题目中要求手上的成品不得超过10 if(j&&s[i]=='A') dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j-1][k][l]); if(k&&s[i]=='B') dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k-1][l]); if(l&&s[i]=='C') dp[i][j][k][l]=min(dp[i][j][k][l],dp[i-1][j][k][l-1]); //取成品的转移方程 dp[i][0][k][l]=min(dp[i][0][k][l],dp[i][j][k][l]+1); dp[i][j][0][l]=min(dp[i][j][0][l],dp[i][j][k][l]+1); dp[i][j][k][0]=min(dp[i][j][k][0],dp[i][j][k][l]+1); //装箱 } printf("%lld ",dp[n][0][0][0]);//输出 //return 0; }