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

过河卒
Time Limit: 5000 MSMemory Limit: 65536 K
Total Submit: 152(35 users)Total Accepted: 33(21 users)Rating: Special Judge: No
Description

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值