5.8:Hoof, Paper, Scissor G(蹄子,剪刀,布)
思路:动态规划
状态设计:
F [ i ] [ j ] [ k ] 表示第i轮,变换了j次手势,且最后一次出的是k
状态计算:
首先,如果下一轮的出拳和和上一轮一样的话,也就是不用边
f[i][j][k] = f[i - 1][j][k]
如果变的话,设上一轮出拳是x(x与k不相同)
f[i][j][k] = f[i - 1][j - 1][x]
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<sstream>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<string>
#include<vector>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define mem(a) memset(a,0,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define inf 0x3f3f3f3f
#define sf(n) scanf("%d", &n)
#define endl '\n'
#define cyes cout<<"yes"<<endl
#define debug(x) cout<<"-----"<<x<<endl
using namespace std;
const int N = 1e5 + 5;
int n, m;
int f[N][25][4];
int get() //字母转换为数字
{
char ch; cin >> ch;
if(ch == 'H') return 0; //石头
if(ch == 'S') return 1; //剪刀
if(ch == 'P') return 2; //布
}
int check(int a, int b) //检查a是否能赢b
{
return (a + 1) % 3 == b;
}
int main()
{
IOS;
cin >> n >> m;
for(int i = 1; i <= n; i++) //枚举第几轮
{
int x = get(); //得到对手的手势
for(int j = 0; j <= min(i, m); j++) //枚举变换几次
for(int k = 0; k < 3; k++) //枚举出的手势
{
f[i][j][k] = f[i - 1][j][k] + check(k, x); //不变
if(j) //变
{
int a = (k + 1) % 3;
f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][a] + check(a, x));
a = (a + 1) % 3;
f[i][j][k] = max(f[i][j][k], f[i - 1][j - 1][a] + check(a, x));
}
}
}
int res = 0;
for(int j = 0; j <= m; j++) //在所有可能的情况中取一个最大值
for(int k = 0; k < 3; k++)
res = max(res, f[n][j][k]);
cout << res << endl;
return 0;
}