◆考试题目◆◇NOIP模拟赛◇turtle(乌龟)

◇NOIP模拟赛◇turtle


Description
一只乌龟由于智商低下,它只会向左或向右走,不过它会遵循主人小h的指令:F(向前走一步),T(掉头)。现在小h给出一串指令,由于小h有高超的计算能力,他可以马上知道乌龟最后走到哪里。
为了难倒小h,他的好朋友小c就说,现在让你修改其中n个指令,使得乌龟移动到离起点最远的地方。(修改是指“T”变成“F”,或“F”变成“T”,可以对同一个指令多次修改)。乌龟一开始在0点。

Input
第1行:一个字符串S代表指令 ( 0<len100 )
接下来一行一个整数n,表示要修改的指令个数 ( 0n50 )
Output
第1行:一个整数,表示乌龟所能移动到的最远距离。

Sample Input

FFFTFFF
2

Sample Output

6

题目解析
这道题是一道有些变化的 资源分配DP 问题——将 j 次修改机会分配在前 i 个命令中。有变动的是阅读到某一命令时可以有向左或向右两种情况,于是在原来的状态数组 (g[i][j] ) 中增加一维,表示阅读到第i条指令时的方向(不妨设1向右,0向左)。
我们把乌龟爬的那一段直线抽象为一个数轴,它一开始在原点,最后它离原点的距离即它行走到的位置的绝对值(绝对值的几何意义),且由于一开始乌龟的方向并不影响最后的结果,我们不妨设乌龟一开始向右(正半轴)。这样就有一个问题——最后乌龟可以在数轴的正半轴,也可以在负半轴。那么我们就需要分别存阅读到第i条指令时的最小值和最大值——用 struct 存在一起。
那么数组就变成了这样:

struct Ans{int big,small;Ans() {big=-1e8,small=1e8;}}g[100][50][2];

注意定义时用构造函数分别给最大、最小值初始化。
接下来就是常规的 记忆化搜索 ,函数里的每一个参数都与数组 g 一一对应。注意它的返回值也是 Ans 。首先判断边界,当 len(当前阅读到的指令位置,从0开始)<0 ,也就是指令全部阅读完,就返回一个 “空” ,这里的空是一个 Ans 变量,那么我们就可以定义一个变量(Nothing)表示 “空” ,然后经过记忆化优化。
我们定义两个 Ans 变量(F1 , F2)分别表示不改变当前指令的值和改变当前指令的值。然后根据当前指令时 F 还是 T 分2类。由于必须把机会用完(由于一条指令可以改无数次,且当一条指令改偶数次时该指令是不变的,所以必须保证最后还剩余偶数次修改的机会),这里有一种情况是不能不修改的——当阅读到最后一条指令(len==0)时,剩余奇数次机会;同样有一种情况是必须不修改的——当阅读到最后一条指令时,剩余偶数次机会。排除这两种情况后,得出 F1 , F2 的值。g 的 big 和 small 就分别对应 F1 和 F2 中的 big 的较大值和 small 的较小值。
最后输出 g[len][n][1] 的 big 和 small 绝对值的最大值。


程序样例
卡了一点数据,节省空间

/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<cmath>
#define max(a,b) (a>b? a:b)
#define min(a,b) (a<b? a:b)
char code[100];
struct Ans
{
    int big,small;
    Ans() {big=-1e8,small=1e8;}
}g[100][50][2],Nothing;
bool vis[100][50][2];
Ans G(int len,int change,bool lr)
{
    if(len<0) return Nothing;
    if(vis[len][change][lr]) return g[len][change][lr];
    vis[len][change][lr]=true;
    int Flag=lr? 1:-1;
    Ans F1,F2;
    if(code[len]=='F')
    {
        if(len || change%2==0) F1=G(len-1,change,lr),F1.big+=Flag,F1.small+=Flag;
        if((len || (!len && change%2)) && change) F2=G(len-1,change-1,!lr);
    }
    else
    {
        if(len || change%2==0) F1=G(len-1,change,!lr);
        if((len || (!len && change%2)) && change) F2=G(len-1,change-1,lr),F2.big+=Flag,F2.small+=Flag;
    }
    g[len][change][lr].big=max(F1.big,F2.big);g[len][change][lr].small=min(F1.small,F2.small);
    return g[len][change][lr];
}
int main()
{
    Nothing.big=Nothing.small=0;
    int change;
    gets(code);scanf("%d",&change);
    Ans ans=G(strlen(code)-1,change,1);
    printf("%d",(int)max(fabs(ans.big),fabs(ans.small)));
    return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值