Hoof, Paper, Scissors(USACO)

题目大意:

一种游戏(类似于石头剪刀布):两个人分别给出一个字母,然后比较:H>S,S>P,P>H,我们已知对手的字母顺序,求在前n局中我们最多能赢多少次。

由于出字母的人非常懒,所以开局后会选定一种字母,中途只会改变k次,剩余状态下只会不停重复上一次出的字母,所以请你解决这个问题;

————————————————我是分割线————————————————

好吧,这道题就是DP题。

f[i][j][k]表示出到第i局,改变了j次,目前出的是第k个字母的最多赢的局数。

然后每次DP可以从f[i-1][j][k]和f[i-1][j-1][l(l!=k)]转移

然后就是统计f[n][k][0-2],取最大值即可

下面贴代码

#include<cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int ds[100005];
char ch;
int f[2][21][3];
int n,tot,ans;
void swap(int &a,int &b){
    int tmp;
    tmp=a;a=b;b=tmp;
}
int main(){
    freopen("GP2.in","r",stdin);
    freopen("GP2.out","w",stdout);
    scanf("%d%d",&n,&tot);
    for(int i=1;i<=n;i++){
        scanf("%s",&ch);
        if(ch=='H')ds[i]=0;
        else if(ch=='S')ds[i]=1;
        else ds[i]=2;
    }    
    int pre=0,lst=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=tot;j++)
            for(int k=0;k<=2;k++)
            {
                for(int l=0;l<=2;l++)
                {
                    if(k==l)f[lst][j][k]=max(f[lst][j][k],f[pre][j][l]);
                    else if(j)f[lst][j][k]=max(f[lst][j][k],f[pre][j-1][l]);    
                }
                f[lst][j][k]+=(ds[i]==(k+1)%3);
            }
        swap(pre,lst);        
    }
    for(int i=0;i<=tot;i++)
        for(int j=0;j<=2;j++)
            ans=max(ans,f[pre][i][j]);
    printf("%d
",ans);                
    fclose(stdin);
    fclose(stdout);
}
原文地址:https://www.cnblogs.com/ghostfly233/p/7027854.html