1. 程式人生 > >hrbust/哈理工oj 1042 過河卒【記憶化搜尋】

hrbust/哈理工oj 1042 過河卒【記憶化搜尋】

過河卒

Time Limit: 5000 MS

Memory Limit: 65536 K

Total Submit: 162(35 users)

Total Accepted: 34(22 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

分析:首先,對於這個題來講,因為有很多格子有可能會重複走的情況,所以我們第一個要處理的問題就是判重問題,辣麼如何判重呢?第一反應是狀壓, 但是K因為比較多,這種方法還是行不通的,那如果一路特判各種if、else估計應該可以,但是還是比較複雜,這裡我們採用記憶化搜尋的方法來解題。

思路:

首先我們對於K的重複拿取要有相應的判斷,我們可以用兩個變數l、r來表示當前行走到的最左端和最右端,當然如果想拿一個K,當然這個K一定不是在l、r之間的。這樣我們就能夠解決了重複拿取K的問題,辣麼如何搞定l、r到底放在哪裡最好呢?我們乾脆不要考慮,用dp的思想,能夠列舉的可能都枚舉出來,我們也就不需要貪心搞這一部分了,辣麼不難想到dp陣列我們這樣設定:

dp【x】【y】【step】【l】【r】;表示的含義還是淺顯易懂的。

辣麼狀態轉移方程嘞?一共有三種走法,辣麼我們控制三種走法即可:

dp【x】【y】【step】【l】【r】=max(dp【x-1】【y】【step-1】【l】【r】(我們用a來表示),dp【x】【y-1】【step-1】【l】【r】(我們用b來表示),dp【x】【y+1】【step-1】【l】【r】(我們用c來表示));

因為涉及到l、r的變化問題,我們涉及到細節的處理:

對於a:

首先要控制x大於0

a=dp【x-1】【y】【step】【y】【y】+(map【x-1】【y】==‘K'?1:0);

對於b:

首先要控制y大於0

然後如果y大於l辣麼b=dp【x】【y-1】【step】【l】【r】否則,b=dp【x】【y-1】【step】【l-1】【r】+(map【x】【y-1】==‘K'?1:0)【因為只有這種情況才不會重複拿取K】

對於c:

首先要控制y小於8(因為y+1==8,如果y==8那麼y+1==9屬於非法操作)

然後如果y小於r辣麼c=dp【x】【y+1】【step】【l】【r】否則,c=dp【x】【y-1】【step】【l】【r+1】+(map【x】【y-1】==‘K'?1:0)

所有操作搞定完畢,最後就是程式碼實現部分:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int k;
char a[15][15];
int dp[7][11][105][11][11];
int sx,sy;
int check(int x,int y)
{
    if(a[x][y]=='K')return 1;
    else return 0;
}
int dfs(int x,int y,int step,int l,int r)
{
    if(dp[x][y][step][l][r]==-1)
    {
        if(step==0)return dp[x][y][step][l][r]=0;
        int maxn=0;
        if(x>0)
        maxn=max(maxn,dfs(x-1,y,step-1,y,y)+check(x-1,y));
        if(y>0)
        {
            if(y>l)maxn=max(maxn,dfs(x,y-1,step-1,l,r));
            else maxn=max(maxn,dfs(x,y-1,step-1,l-1,r)+check(x,y-1));
        }
        if(y<8)
        {
            if(y<r)maxn=max(maxn,dfs(x,y+1,step-1,l,r));
            else maxn=max(maxn,dfs(x,y+1,step-1,l,r+1)+check(x,y+1));
        }
       // printf("%d\n",maxn);
        return dp[x][y][step][l][r]=maxn;
    }
    else return dp[x][y][step][l][r];
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,-1,sizeof(dp));
        scanf("%d",&k);
        for(int i=0; i<5; i++)
        {
            scanf("%s",a[i]);
            for(int j=0; j<9; j++)
            {
                if(a[i][j]=='L')
                {
                    sx=i;
                    sy=j;
                }
            }
        }
        printf("%d\n",dfs(sx,sy,k,sy,sy));
    }
}