2015百度之星資格賽1005

題目名稱:下棋

題目鏈接:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=584&pid=1005

Problem Description

NM的棋盤上有一個受傷的國王與一個要去救援國王的騎士,他們每個單位時間必須同時移動一次尋找對方。如下圖所示,黑色的圖例表示國王(右)或騎士(左)當前所在的位置,那麼灰色的位置表示在一次移動中他們可能到達的位置。國王傷勢嚴重,因此他必須在K個單位時間內得到騎士的救援,否則會掛掉。問國王是否可以在K個單位時間內獲得救援,如果可以,最短需要花多少個單位時間。

Input

第一行包含一個整數T,1T50代表測試數據的組數,接下來T組測試數據。

每組測試數據第一行包含三個整數N,M,K, 且2N,M10001K200。第二行兩個整數Xking,Yking,對應國王所在方格的座標。第三行兩個整數Xknight,Yknight,對應騎士所在方格的座標。其中1Xking,XknightN,1Yking,YknightM,保證騎士與國王一開始不在同一個方格內且他們都可以移動。:

Output

對於每組測試數據,輸出兩行:

第一行輸出:"Case #i:"。i代表第i組測試數據。

第二行輸出測試數據的結果,如果國王可以得到救援,則輸出最快需要花多少個單位時間。否則,輸出“OH,NO!”。

Sample Input
2
3 2 1
1 1
3 1
3 3 1
1 1
1 2 
Sample Output
Case #1:
1
Case #2:
OH,NO!


思路:先對國王和騎士bfs,推出所有走到可能。然後再尋找最少時間的(這道題感覺還不錯,可惜hdu沒得提交了)


代碼如下:

#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#define clr(a,val) memset(a,val,sizeof(a))
using namespace std;
const int maxn = 1005;
const int INF = 0x3f3f3f3f;
struct SPoint
{
    int x,y,step;
};
int N,M,K;
SPoint Knight,King,Now,Next;
queue<SPoint>Que;
int Map_Knight[maxn][maxn],Map_King[maxn][maxn];
bool vis[maxn][maxn];
const int dirX_Knight[8] = {-1,-2,-2,-1,1,2,2,1};
const int dirY_Knight[8] = {-2,-1,1,2,-2,-1,1,2};
const int dirX_King  [8] = {-1,0,-1,1,-1,1,0,1 };
const int dirY_King  [8] = {-1,-1,0,1,1,-1,1,0 };
bool Over_Bound(const SPoint &p)
{
    return p.x <= 0 || p.y <= 0 || p.x > N || p.y > M;
}
void BFS_Knight()
{
    clr(vis,false);
    clr(Map_Knight,-1);
    while(!Que.empty()) Que.pop();
    Que.push(Knight);
    vis[Knight.x][Knight.y] = true;
    while(!Que.empty())
    {
        Now = Que.front();
        Map_Knight[Now.x][Now.y] = Now.step;
        for(int i = 0; i < 8; i++)
        {
            Next.x = Now.x + dirX_Knight[i];
            Next.y = Now.y + dirY_Knight[i];
            Next.step = Now.step + 1;
	    //Next.step > K 剪枝處理
            if(Over_Bound(Next) || vis[Next.x][Next.y] || Next.step > K)
                continue;
            vis[Next.x][Next.y] = true;
            Que.push(Next);
        }
        Que.pop();
    }
}
void BFS_King() {
    clr(vis,false);
    clr(Map_King,-1);
    while(!Que.empty()) Que.pop();
    Que.push(King);
    vis[King.x][King.y] = true;
    while(!Que.empty())
    {
        Now = Que.front();
        Map_King[Now.x][Now.y] = Now.step;
        for(int i = 0; i < 8; i++)
        {
            Next.x = Now.x + dirX_King[i];
            Next.y = Now.y + dirY_King[i];
            Next.step = Now.step + 1;
	    //Next.step > K 剪枝處理
            if(Over_Bound(Next) || vis[Next.x][Next.y] || Next.step > K)
                continue;
            vis[Next.x][Next.y] = true;
            Que.push(Next);
        }
        Que.pop();
    }
}
int main()
{
    int t,cas = 0,ans;
    cin>>t;
    while(t--)
    {
        cin>>N>>M>>K;
        cin>>King.x>>King.y;
        cin>>Knight.x>>Knight.y;
        King.step = Knight.step = 0;
        BFS_Knight();
        BFS_King();
        ans = INF; //初始化爲無窮大
	//關鍵得好好理解下面的代碼~
        for(int i = 1; i <= N; i++)
        {
            for(int j = 1; j <= M; j++)
            {
                int& Step_King = Map_King[i][j], &Step_Knight = Map_Knight[i][j];
                if(Step_King == -1 || Step_Knight == -1) continue;
		//分類的主要依據就是國王的走法和騎士不同
		//如果國王比騎士先到該點,國王可以現在該點附近轉一下,並不影響騎士到達該點的步數~
                if(Step_Knight > Step_King)
                {
                    ans = min(ans, Step_Knight);
                    continue;
                }
		//如果國王比騎士到達該點要多走的步數爲奇數
                if((Step_King - Step_Knight) & 1)
                {
                    ans = min(ans,Step_King + 1);
                    continue;
                }
		//如果國王比騎士到達該點要多走的步數爲偶數
                ans = min(ans,Step_King);
                continue;
            }
        }
        printf("Case #%d:\n",++cas);
        if(ans > K) printf("OH,NO!\n");
        else printf("%d\n",ans);
    }
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章