P1443 馬的遍歷

題目:有一個n*m的棋盤(1<n,m<=400),在某個點上有一個馬,要求你計算出馬到達棋盤上任意一個點最少要走幾步html

很早的時候就知道這題是一道裸廣搜,但由於我一直拈輕怕重的學習,因此一直沒有學習廣搜,昨天看到這道題的時候我就知道是時候把以前欠下的債都補回來了!ios

推薦文章:http://www.javashuo.com/article/p-rnbscagb-c.html     對對對這是lixx大佬寫的,超級清晰,有興趣的同窗能夠去看一下(是真的很清晰,反正我看這篇博客會了
數組

而後這道題好像也沒有什麼特別坑的地方(除了輸出),我就直接給大家講一下AC代碼把,不過坑我仍是會說的嗯。函數

我由於輸出WA了2次(1次0分,1次30分),由於數組開小了WA了4次(4次90分)學習

首先這是咱們須要定義的變量以及數組,數組必定不能開小,我一開始開了1萬覺得已經夠大了,結果RE了好屢次:spa

int n,m,mx,my,book[410][410],a=0,b=0,la[410][410];
//book數組是用來標記的,由於廣搜第一次遇到的必定是最小的步數,咱們在他第一次遇到的時候就把他標記起來,就不會被覆蓋一些不正確的值了。la在這裏是用來存每一個格子的步數的(以便於輸出)。n,m,mx,my分別是須要輸入的四個數。a和b分別是廣搜中的頭和尾。
int dx[10]={-1,1,-1,1,2,2,-2,-2},xx=0;
//dx是當前這個點能到達的8個方向的x值(就是咱們要每次都讓當前這個點的x座標加上這其中的一個數,固然y也得加同下標的y值,就能夠獲得一個新的,剛纔那個點能到達的八個座標中的一個了),xx表示的是每次加上dx值的x座標。
int dy[10]={-2,-2,2,2,1,-1,1,-1},yy=0;
//dy數組道理與上面的dy相同,yy與xx相同。
int x[100010],y[100010],bushu[10010];
//x是用來存x座標值的,y是用來存y座標的,bushu是用來存每一步的步數的,這三個數組是關鍵!!

下面是main函數裏面的東西,輸入我就不說了,反正你們都會嘛,咱們直接來看廣搜這一部分,我感受註釋已經儘可能寫的很詳細了:code

    x[a]=mx;//這裏能夠說是在初始化,讓起點的x和y都等於馬所在的x和y 
    y[a]=my;
    a++;//a是尾,添加了新元素咱們就讓尾加加
    //是的咱們就是在模擬隊列,你直接用queue也能夠啦,不過我更喜歡用數組模擬(主要是由於不會) 
    while(b<a){//while若是頭<尾那麼就運行,也就是若是頭>=尾就結束,表示這個廣搜結束了搜完了(都搜完了你還搜那可就厲害了) 
        for(int i=0;i<8;i++){//模擬八個方向 
            xx=x[b]+dx[i];//每次讓xx和yy都分別加上dx和dy 
            yy=y[b]+dy[i];//這裏解釋下爲何讓x[b]和y[b]加dx、dy呢
            //由於x[b]和y[b]是他們的根源,也能夠說是他倆的爸爸,兒子確定是在爸爸的基礎上加的呀
            if(xx>0&&xx<=n&&yy>0&&yy<=m&&book[xx][yy]==0){//判斷這個新座標是否越界以及是否判斷過 
                book[xx][yy]=1;//若是沒有被判斷過,那麼咱們就標記一下,讓他之後不在判斷了,也就是說只判斷這一次
                //只判斷一次獲得的值必定是最小值 
                x[a]=xx;//更新x數組 
                y[a]=yy;//更新y數組 
                bushu[a]=bushu[b]+1;//步數也要更新啦,固然也要等於他爸爸的步數+1 
                la[xx][yy]=bushu[a];//這個數組la是用來輸出的,會很方便 
                a++;//由於有了新的x和y咱們也要讓尾巴加個一啦 
            }
        }
        b++;//頭每次+1,也就是每次都幫一個爸爸找兒子,一直找到找完爲止 
    }

但願兒子爸爸這個比喻可讓大家看懂,李老師常常這樣給咱們講課,很清晰的(๑•̀ㅂ•́)و✧htm

接下來是輸出的問題,你們必定要注意看哈:blog

la[mx][my]=0;//讓最開始馬的座標=0,由於馬不須要走就在那個座標上了,再標記一遍更保險點 
    for(int i=1;i<=n;i++){//for嵌套輸出步數 
        for(int j=1;j<=m;j++){
            if(la[i][j]==0){//若是當前的步數=0,表示這個座標要麼是馬一開始的座標,要麼就是馬去不了的地方 
                if(i==mx&&j==my) la[i][j]=0;//這一句其實沒啥用啦,主要是咱們須要用else
                //若是直接判斷if(i!=mx&&j!=my)的話萬一其中恰好有一個行數是i或者列數是j就會死得很慘 
                else la[i][j]=-1;//若是他既等於零並且又不是馬一開始的座標的話就說明這個馬去不了的地方,題目要求去不了的地方輸出-1 
            }
            printf("%-5d",la[i][j]);//%-5d是一個很實用的,查了不少資料才曉得,既能夠左對齊又可讓他輸出的場寬爲5,完美 
        }
        printf("\n");//每輸出滿一行就回車 
    }
    return 0;//return 0不能忘

我第一次就錯在場寬爲5這上面了,第二次錯在馬一開始的座標上面,我好南qwq隊列

下面放一下完整代碼啦:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,mx,my,book[410][410],a=0,b=0,la[410][410];
int dx[10]={-1,1,-1,1,2,2,-2,-2},xx=0,bx=0;
int dy[10]={-2,-2,2,2,1,-1,1,-1},yy=0,by=0;
int x[100010],y[100010],bushu[100010];
int main(){
    scanf("%d%d%d%d",&n,&m,&mx,&my);
    x[a]=mx;//這裏能夠說是在初始化,讓起點的x和y都等於馬所在的x和y 
    y[a]=my;
    a++;//a是尾,添加了新元素咱們就讓尾加加
    //是的咱們就是在模擬隊列,你直接用queue也能夠啦,不過我更喜歡用數組模擬(主要是由於不會) 
    while(b<a){//while若是頭<尾那麼就運行,也就是若是頭>=尾就結束,表示這個廣搜結束了搜完了(都搜完了你還搜那可就厲害了) 
        for(int i=0;i<8;i++){//模擬八個方向 
            xx=x[b]+dx[i];//每次讓xx和yy都分別加上dx和dy 
            yy=y[b]+dy[i];//這裏解釋下爲何讓x[b]和y[b]加dx、dy呢
            //由於x[b]和y[b]是他們的根源,也能夠說是他倆的爸爸,而後他若是要一個新的兒子的話,確定是在爸爸的基礎上加的 
            if(xx>0&&xx<=n&&yy>0&&yy<=m&&book[xx][yy]==0){//判斷這個新座標是否越界以及是否判斷過 
                book[xx][yy]=1;//若是沒有被判斷過,那麼咱們就標記一下,讓他之後不在判斷了,也就是說只判斷這一次
                //只判斷一次獲得的值必定是最小值 
                x[a]=xx;//更新x數組 
                y[a]=yy;//更新y數組 
                bushu[a]=bushu[b]+1;//步數也要更新啦,固然也要等於他爸爸的步數+1 
                la[xx][yy]=bushu[a];//這個數組la是用來輸出的,會很方便 
                a++;//由於有了新的x和y咱們也要讓尾巴加個一啦 
            }
        }
        b++;//頭每次+1,也就是每次都幫一個爸爸找兒子,一直找到沒爸爸爲止 
    }
    la[mx][my]=0;//讓最開始馬的座標=0,由於馬不須要走就在那個座標上了,再標記一遍更保險點 
    for(int i=1;i<=n;i++){//for嵌套輸出步數 
        for(int j=1;j<=m;j++){
            if(la[i][j]==0){//若是當前的步數=0,表示這個座標要麼是馬一開始的座標,要麼就是馬去不了的地方 
                if(i==mx&&j==my) la[i][j]=0;//這一句其實沒啥用啦,主要是咱們須要用else
                //若是直接判斷if(i!=mx&&j!=my)的話萬一其中恰好有一個行數是i或者列數是j就會死得很慘 
                else la[i][j]=-1;//若是他既等於零並且又不是馬一開始的座標的話就說明這個馬去不了的地方,題目要求去不了的地方輸出-1 
            }
            printf("%-5d",la[i][j]);//%-5d是一個很實用的,查了不少資料才曉得,既能夠左對齊又可讓他輸出的場寬爲5,完美 
        }
        printf("\n");//每輸出滿一行就回車 
    }
    return 0;//return 0不能忘
}

以上僅是我的對於這道題的所有思路與想法,若是有什麼不對的地方,還請各位大佬及時向我糾正。

相關文章
相關標籤/搜索