题目描述:
1657 电子龟
电子龟的行动,是沿着直线左右走动的。他能够接受两种指令,“T”(向后转,
即如果面向左,改成向右;否则就向左)和“F”(向当前面朝的方向往前移动
一个单位距离)。
现在给出一串指令,让电子龟来执行。你必须改动n次指令,一次改变一个(一个
指令可以改动多次)。使得电子龟执行完所有的指令后,离起始点最远。
样例解释:
在第一个样例中,最好方案是把“T”变成“F”,最远距离为2。
在第二个样例中,最好方案是把第四个变成“F”,然后把最后一个或者第一个变成“T”。
收起
输入
单组测试数据 第一行是一个字符串S,代表原始的指令串,只包含'T','F'字符。(1≤|S|≤100) 第二行是一个整数n,表示要对指令作多少次改变。(1≤n≤50)输出
共一行,一个整数,表示电子龟执行完所有的指令后,离起始点的最远距离。输入样例
FT 1 FFFTFFF 2输出样例
2 6
题解解释(注意区分阶段、状态):
可以用三维dp来保存状态, dp[i][j][k]表示在前i个字符变换了j步之后方向
为k(k = 1 or k = 0)的最优解,也就是离原点的最大距离。这里规定0方向为正
方向,1位负方向,表示的是当前这个人朝哪个方向。这两个方向是对立的。
所以就可以递推一个关系式,分第i个字符为'F' or 'T'时
如果为'F'
依次枚举在第i个位置变换了几步,这是枚举的范围为0~j, 假设变换了k步
(和上面的
当中的k不是一个)
1. 如果当k为奇数的时候,就是相当于变化了1步,所以'F'就变成'T'了,
那么他的方向也因此变化了。所以当前的方向一定和上一步(也就是i - 1时的方
向)的方向相反,所以有:
,
2.如果k为偶数,相当于没有变化,所以还是字符'F',如果是正方向,
那么他就可以由上一步继续向正方向走一步,也就是加1, 如果是负方向,相
当于往回走一步,距离就减1,递推方程为
;
;
如果为'T'
依次枚举在第i个位置变化了几步,范围也是0~j,假设变换k步
1.如果k为奇数,这时就变化成了'F',所以:
2.如果k为偶数,这时还是'T',所以:
其中还有一个问题就是和刚开始的方向的无关,不用管朝哪个方向,
只要走的最远的就行了,而且始终有两个相互对立的方向。初始化的
时候
和
都得初始化0,这样才可以往哪走都可以。
代码实现:
#include<iostream>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+100;
int dp[120][60][2];
char str[N];
int main() {
int n,len,ans;
while(scanf("%s",str+1)!=EOF) {
scanf("%d",&n);
memset(dp,-INF,sizeof(dp));//ps:有负数解,注意-inf
len=strlen(str+1);
dp[0][0][0]=dp[0][0][1]=0;//注意边界
for(int i=1; i<=len; i++) {
for(int j=0; j<=n; j++) {
for(int k=0; k<=j; k++) {
if(str[i]=='F') {
//状态确定后,转移不难理解
if(k&1) {
dp[i][j][0]=max(dp[i][j][0],dp[i-1][j-k][1]);
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-k][0]);
} else {
dp[i][j][0]=max(dp[i][j][0],dp[i-1][j-k][0]+1);
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-k][1]-1);
}
} else {
if(k&1) {
dp[i][j][0]=max(dp[i][j][0],dp[i-1][j-k][0]+1);
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-k][1]-1);
} else {
dp[i][j][0]=max(dp[i][j][0],dp[i-1][j-k][1]);
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-k][0]);
}
}
}
}
}
//目标状态
ans=max(dp[len][n][0],dp[len][n][1]);
cout<<ans<<endl;
}
return 0;
}
THE END;