hrbustOJ 1042 过河卒 (dp 搜索应该也可以写)

来源:互联网 发布:windows测试页打印失败 编辑:程序博客网 时间:2024/06/05 09:23
过河卒Time Limit: 5000 MSMemory Limit: 65536 KTotal Submit: 152(35 users)Total Accepted: 33(21 users)Rating: Special Judge: NoDescription

Lda学会了中国象棋,在一次与Kevin的切磋中,Lda不幸只剩下一只过河卒了,而Kevin还有很多棋子。

 

过河卒在棋盘上能移动的范围是一个5×9的平面(如图)。据Kevin介绍,过河卒每一步都可以选择向前、左、或右移一格,但是不能后退,也不能移出棋盘边界。途中如果经过敌人的棋子,那么敌人的棋子就被吃掉了。

考虑到Lda初学,为了能让游戏不至于过快结束,Kevin决定让Lda的过河卒连走k步,在这k步中Kevin不走棋。Lda希望在这k步中他能吃掉尽可能多的棋子,请问他最多能吃掉Kevin多少棋子呢?

Input

第一行一个正整数T,表示测试数据的组数。接下来每组数据第一行一个正整数k (k ≤ 100),表示Lda可以连续走棋的步数。然后接下来的5行表示棋盘状态,每行一个9个字符的字符串,其中’*’表示没有棋子,’K’表示有Kevin的棋子,’L’表示这里是Lda的过河卒的初始位置(棋盘上有且只有一个’L’)

Output

每组数据输出一行,表示Lda最多能吃掉的棋子数。

Sample Input

3

5

**KKK****

****K****

**K*K**K*

KK****L**

**K******

9

*********

**K******

*********

**K****K*

******L**

8

*********

**K******

*********

**K****K*

******L**

Sample Output

3

3

2


简单的说dp[i][j][k]  代表处理完第i行 最终在i行j列  消灭k个棋子的最小花费

然后考虑dp[i][j][k] 从dp[i+1][fj][fk]的转移  枚举一下即可

从这个转移我们知道在i行的时候

起点是fj 终点是j  要求消灭至少k-fk个棋子

暴力计算一下最小花费  即可完成转移

还可以优化一下  比如求花费可以记忆化之类的   但是无所谓啦  题目时限五秒 复杂度很OK了

#include<stdio.h>#include<string.h>#include<math.h>#include<iostream>#include<algorithm>using namespace std;int dp[7][10][60];char s[10][10];int get(int num,int fr,int to,int i){    int hav=0;int j,k;    for(j=1;j<=9;j++) if(s[i][j]=='K') hav++;    if(hav<num) return -1;    int l=min(fr,to),r=max(fr,to);    int ret=200;    for(j=1;j<=l;j++)    for(k=r;k<=9;k++)    {        hav=0;        for(int ii=j;ii<=k;ii++)            if(s[i][ii]=='K') hav++;        if(hav<num) continue;        ret=min(ret,k-j+l-j+k-r);    }    return ret;}int main(){    int i,j,K,k;    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d",&K);        int ans=0,vis;        memset(dp,-1,sizeof(dp));        K++;        for(i=1;i<=5;i++)        {            scanf("%s",s[i]+1);        }        for(i=1;i<=5;i++) for(j=1;j<=9;j++) if(s[i][j]=='L') dp[i+1][j][0]=0,vis=i;        for(i=vis;i>=1;i--)        {            for(j=1;j<=9;j++)            {                for(k=0;k<=50;k++)                for(int fj=1;fj<=9;fj++)                {                    for(int fk=0;fk<=k;fk++)                    {                        if(dp[i+1][fj][fk]==-1) continue;                        int d=get(k-fk,fj,j,i);                        if(d==-1) continue;                        if(dp[i][j][k]==-1) dp[i][j][k]=dp[i+1][fj][fk]+d+1;                        else dp[i][j][k]=min(dp[i][j][k],dp[i+1][fj][fk]+d+1);                        if(dp[i][j][k]<=K) ans=max(k,ans);                    }                }            }        }        printf("%d\n",ans);    }    return 0;}


0 0