簡單搜索poj 2243(水

應該也不算一題多解。
就是閒的。。也是因爲這題比較簡單而且在網上看了別人寫的特別好,就想用這題當入門練一下(逃
https://vjudge.net/problem/POJ-2243
題意:
8*8的棋盤,馬走斜日,馬走幾步可以達到給出的終點?

方法一:傳統BFS,就不再贅述了,很簡單啦。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define bug cout<<"bugbug"<<endl;
using namespace std;
char a1,a2,b1,b2;
int map[8][8];
struct data{
    int xi,yi;
};
int dx[8]={1,2,2,1,-1,-2,-2,-1};
int dy[8]={2,1,-1,-2,-2,-1,1,2};
int judge(data temp,int x2,int y2){
    if(temp.xi==x2&&temp.yi==y2) return 1;
    return 0;
}
int bfs(int x1,int y1,int x2,int y2){
    memset(map,-1,sizeof(map));
    queue<data>que;
    data in;
    in.xi=x1;
    in.yi=y1;
    que.push(in);
    map[in.xi][in.yi]=0;
    while(!que.empty()){
        data top,ou;
        top=que.front();
        que.pop();
        if(judge(top,x2,y2)) return map[top.xi][top.yi];
        for(int i=0;i<8;i++){
            ou.xi=top.xi+dx[i];
            ou.yi=top.yi+dy[i];
            if(map[ou.xi][ou.yi]==-1&&ou.xi>=0&&ou.xi<8&&ou.yi>=0&&ou.yi<8){
                que.push(ou);
                map[ou.xi][ou.yi]=map[top.xi][top.yi]+1;
            }
        }
    }
    return 0;
}
int main(){
    //freopen("test.txt","r",stdin);
    while(cin>>a1>>a2>>b1>>b2){
        int ans=bfs(a1-'a',a2-'1',b1-'a',b2-'1');
        printf("To get from %c%c to %c%c takes %d knight moves.\n",a1,a2,b1,b2,ans);
    }
    return 0;
}

順便在這裏加一個小技巧。之前有和同學說過這個。
結構體其實是可以和類一樣用的。可以非默認構造,如果要非默認構造的話,要記得加一個默認構造函數。
還有一個就是爲什麼結構體不能放在set啊,map啊裏面。
因爲set和map的底層是紅黑樹。紅黑樹的話他對內部對象就會排序。就要重載一下小於號。自定義一個小於號。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
struct data{
    int x,y;
    data(int dx,int dy){
        x=dx,y=dy;
    }
    data(){}
    bool operator <(const data b)const{
        return x==b.x?x<b.x:y<b.y;
    }
};
int main(){
    data temp1(1,1);
    data temp2(2,2);
    set<data>se;
    se.insert(temp1);
    se.insert(temp2);
    if(se.count(temp1)) cout<<temp1.x<<" "<<temp1.y<<endl;
    return 0;
}

方法二:傳統DFS。這個還真的蠻。。。有點小意思吧。而且對這道題的分類也是BFS(hhh分類的人可能是TLE了DFS
我寫了一個我認爲很對的剪枝其實並沒有剪到什麼(逃
我還感覺寫得蠻對的。結果TLE了兩發。。。這我就很不能理解啦。
我一開始DFS函數是這麼寫的。

void dfs(int x1,int y1,int x2,int y2,int step){
    if(judge(x1,y1,x2,y2)){
        ans=min(ans,step);
        return;
    }
    if(step>=ans) return;//這就是我說的沒什麼用的剪枝,發現當前步數(不管找到了沒有)比ans大了就直接剪掉。其實也減到了不少,但是對這道題來說確實是。。。嗯。。不夠。
    for(int i=0;i<8;i++){
        int xx=dx[i]+x1;
        int yy=dy[i]+y1;
        if(map[xx][yy]==-1&&xx>=0&&xx<8&&yy>=0&&yy<8){
            map[xx][yy]=1;
            dfs(xx,yy,x2,y2,step+1);
            map[xx][yy]=-1;
        }
    }
}

超有道理的。對不對。
隨後想到,如果我想要剪枝跟有效那我是不是要使ans迅速的變小或者使每一步都能判斷出他是否有效。
於是,如果對於一個點 map[x][y]我已經到過這個點,並且我上次到這一點的步數小於這一次的,(這是深搜嘛,廣搜就不會遇到這樣的問題。)那當前我這條路走下去肯定沒有上一次那麼走棒,所以我可以對map數組進行更新,使得map數組裏的值儘量地小,這樣就方便我下一次把它剪掉。
其實也很容易就想到了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define bug cout<<"bugbug"<<endl;
using namespace std;
char a1,a2,b1,b2;
int map[8][8];
int dx[8]={1,2,2,1,-1,-2,-2,-1};
int dy[8]={2,1,-1,-2,-2,-1,1,2};
int judge(int x1,int y1,int x2,int y2){
    if(x1==x2&&y1==y2) return 1;
    return 0;
}
int ans=1e9+7;
void dfs(int x1,int y1,int x2,int y2,int step){
    if(judge(x1,y1,x2,y2)){
        ans=min(ans,step);
        return;
    }
    if(map[x1][y1]==-1||map[x1][y1]>step) map[x1][y1]=step;
    if(map[x1][y1]<step) return;
    if(step>=ans) return;
    for(int i=0;i<8;i++){
        int xx=dx[i]+x1;
        int yy=dy[i]+y1;
        if(xx>=0&&xx<8&&yy>=0&&yy<8){
            dfs(xx,yy,x2,y2,step+1);
        }
    }
}
int main(){
    //freopen("test.txt","r",stdin);
    while(cin>>a1>>a2>>b1>>b2){
        memset(map,-1,sizeof(map));
        map[a1-'a'][a2-'1']=1;
        ans=1e9+7;
        dfs(a1-'a',a2-'1',b1-'a',b2-'1',0);
        printf("To get from %c%c to %c%c takes %d knight moves.\n",a1,a2,b1,b2,ans);
    }
    return 0;
}

因爲很久沒有寫搜索了,所以。。。練個手。
這題還有很多種解法,我會陸續寫出雙向BFS,A*和純數學解法(感覺很厲害的樣子呢)。

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