sicily 1152 簡單馬周遊 深度優先搜索及回溯算法

1152. 簡單的馬周遊問題

Constraints

Time Limit: 1 secs, Memory Limit: 32 MB , Special Judgephp

Description

在一個5 * 6的棋盤中的某個位置有一隻馬,若是它走29步正好通過除起點外的其餘位置各一次,這樣一種走法則稱馬的周遊路線,試設計一個算法,從給定的起點出發,找出它的一條周遊路線。ios

爲了便於表示一個棋盤,咱們按照從上到下,從左到右對棋盤的方格編號,以下所示:算法

1     2     3       4     5     6數組

7     8     9       10    11       12post

13    14       15    16       17    18ui

19    20       21    22       23    24url

25    26       27    28       29    30spa

馬的走法是「日」字形路線,例如當馬在位置15的時候,它能夠到達二、四、七、十一、1九、2三、26和28。可是規定馬是不能跳出棋盤外的,例如從位置1只能到達9和14。設計

 

Input

輸入有若干行。每行一個整數N(1<=N<=30),表示馬的起點。最後一行用-1表示結束,不用處理。code

Output

對輸入的每個起點,求一條周遊線路。對應地輸出一行,有30個整數,從起點開始按順序給出馬每次通過的棋盤方格的編號。相鄰的數字用一個空格分開。

Sample Input

4
-1

Sample Output

注意:若是起點和輸入給定的不一樣,重複屢次通過同一方格或者有的方格沒有被通過,都會被認爲是錯誤的。

Problem Source

ZSUACM Team Member

Submit
 
#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <cstring>
using namespace std;
typedef struct Coordinate {
    int x;
    int y;
} Coor;
bool visited[31];
int loc[9][10]; //此在5*6格子數組中添加額外的行和列,拓展爲9*10的數組,即設置邊界,便於找到能夠前進的節點 
map<int, Coor> coors; //用於記錄每一個位置的座標 

//得到能夠前進的節點,即符合「日」字形,且未訪問過 
vector<int> getAdjacents(int i, int j) {
    vector<int> result;
    if (loc[i-2][j-1] != 0 && visited[loc[i-2][j-1]] == false)
       result.push_back(loc[i-2][j-1]);
    if (loc[i-2][j+1] != 0 && visited[loc[i-2][j+1]] == false)
       result.push_back(loc[i-2][j+1]); 
    if (loc[i-1][j-2] != 0 && visited[loc[i-1][j-2]] == false)
       result.push_back(loc[i-1][j-2]);
    if (loc[i-1][j+2] != 0 && visited[loc[i-1][j+2]] == false)
       result.push_back(loc[i-1][j+2]);
    if (loc[i+1][j-2] != 0 && visited[loc[i+1][j-2]] == false)
       result.push_back(loc[i+1][j-2]);
    if (loc[i+1][j+2] != 0 && visited[loc[i+1][j+2]] == false)
       result.push_back(loc[i+1][j+2]);
    if (loc[i+2][j-1] != 0 && visited[loc[i+2][j-1]] == false)
       result.push_back(loc[i+2][j-1]);
    if (loc[i+2][j+1] != 0 && visited[loc[i+2][j+1]] == false)
       result.push_back(loc[i+2][j+1]);
    return result;
}

void search(int start, int &steps, stack<int> &road) {
     vector<int> adjacents = getAdjacents(coors[start].x, coors[start].y);
     //當沒有能夠走的下一個格子時 
     if (adjacents.size() == 0) {
        //若是已經走了29步,此時須要檢測是否已經走完了全部節點 
        if (steps == 29) {
           bool complete = true;
           for (int j = 1; j <= 30; j++) {
               if (visited[j] == false) {
                  complete = false;
                  break;
               }
           }
           //是,則回溯輸出依次通過的節點 
           if (complete == true) {
               vector<int> result;
               while(!road.empty()) {
                   result.push_back(road.top());
                   road.pop();
               }
               for (int j = result.size()-1; j >= 0; j--)
                   cout << result[j] << " ";
               cout << endl;
           } else {
              //否,則在保留已經通過了的節點的棧中刪除該節點,同時使步數減一和設置該節點未訪問過來使的能夠
              //經過其餘節點到達該節點 
              visited[road.top()] = false;
              steps--;
              road.pop();
           }
        } else {
              //未達到上限的29步,則直接保留已經通過了的節點的棧中刪除該節點,同時使步數減一和設置該節點未訪問過來使的能夠
              //經過其餘節點到達該節點
              visited[road.top()] = false;
              steps--;
              road.pop();
        }
     } else {
          //當前節點存在相鄰的能夠走的節點,則依次深搜遍歷相鄰節點 
          for (int i = 0; i < adjacents.size(); i++) {
              visited[adjacents[i]] = true;
              steps++;
              road.push(adjacents[i]);
              search(road.top(), steps, road);
          }
          //剛開始這裏未加 !road.empty(),出現runtime error的錯誤,由於在找到該路徑以後,即上面
          //的for循環跳出以後,此時road已經爲空了,因此若是未判斷!road.empty會是空的road調用 
          //此步是解決本題的關鍵,即當遍歷完一個節點的全部相鄰節點後,若是既沒有達到遍歷完全部節點,即!road.empty
          //相鄰節點也沒有一個進棧的,即均不合格,則此時應該回溯,將該棧頂節點出棧,同時設置爲未訪問過,步數減一 
          if (!road.empty() && road.top() == start) {
              visited[road.top()] = false;
              steps--;
              road.pop();
          }
     }
}

int main() {
    memset(loc, 0, sizeof(loc));
    int value = 1;
    for (int i = 2; i <= 6; i++) {
        for (int j = 2; j <= 7; j++) {
            coors[value].x = i;
            coors[value].y = j;
            loc[i][j] = value++;
        }
    }
    
    int start;
    while (cin>>start&&start!=-1) {
          memset(visited, false, sizeof(visited));
          int steps = 0;
          stack<int> road;
          road.push(start);
          visited[road.top()] = true;
          search(road.top(), steps, road);
    }
    return 0;
}
              
// Problem#: 1152
// Submission#: 3021883
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <cstring>
using namespace std;
typedef struct Coordinate {
    int x;
    int y;
} Coor;
bool visited[31];
int loc[9][10]; //此在5*6格子數組中添加額外的行和列,拓展爲9*10的數組,即設置邊界,便於找到能夠前進的節點 
map<int, Coor> coors; //用於記錄每一個位置的座標 

//得到能夠前進的節點,即符合「日」字形,且未訪問過 
vector<int> getAdjacents(int i, int j) {
    vector<int> result;
    if (loc[i-2][j-1] != 0 && visited[loc[i-2][j-1]] == false)
       result.push_back(loc[i-2][j-1]);
    if (loc[i-2][j+1] != 0 && visited[loc[i-2][j+1]] == false)
       result.push_back(loc[i-2][j+1]); 
    if (loc[i-1][j-2] != 0 && visited[loc[i-1][j-2]] == false)
       result.push_back(loc[i-1][j-2]);
    if (loc[i-1][j+2] != 0 && visited[loc[i-1][j+2]] == false)
       result.push_back(loc[i-1][j+2]);
    if (loc[i+1][j-2] != 0 && visited[loc[i+1][j-2]] == false)
       result.push_back(loc[i+1][j-2]);
    if (loc[i+1][j+2] != 0 && visited[loc[i+1][j+2]] == false)
       result.push_back(loc[i+1][j+2]);
    if (loc[i+2][j-1] != 0 && visited[loc[i+2][j-1]] == false)
       result.push_back(loc[i+2][j-1]);
    if (loc[i+2][j+1] != 0 && visited[loc[i+2][j+1]] == false)
       result.push_back(loc[i+2][j+1]);
    return result;
}

void search(int start, int &steps, stack<int> &road) {
     vector<int> adjacents = getAdjacents(coors[start].x, coors[start].y);
     //當沒有能夠走的下一個格子時 
     if (adjacents.size() == 0) {
        //若是已經走了29步,此時須要檢測是否已經走完了全部節點 
        if (steps == 29) {
               vector<int> result;
               while(!road.empty()) {
                   result.push_back(road.top());
                   road.pop();
               }
               for (int j = result.size()-1; j >= 0; j--)
                   cout << result[j] << " ";
               cout << endl;
        } else {
              //未達到上限的29步,則直接保留已經通過了的節點的棧中刪除該節點,同時使步數減一和設置該節點未訪問過來使的能夠
              //經過其餘節點到達該節點
              visited[road.top()] = false;
              steps--;
              road.pop();
        }
     } else {
          //當前節點存在相鄰的能夠走的節點,則依次深搜遍歷相鄰節點 
          for (int i = 0; i < adjacents.size(); i++) {
              visited[adjacents[i]] = true;
              steps++;
              road.push(adjacents[i]);
              search(road.top(), steps, road);
          }
          //剛開始這裏未加 !road.empty(),出現runtime error的錯誤,由於在找到該路徑以後,即上面
          //的for循環跳出以後,此時road已經爲空了,因此若是未判斷!road.empty會是空的road調用 
          //此步是解決本題的關鍵,即當遍歷完一個節點的全部相鄰節點後,若是既沒有達到遍歷完全部節點,即!road.empty
          //相鄰節點也沒有一個進棧的,即均不合格,則此時應該回溯,將該棧頂節點出棧,同時設置爲未訪問過,步數減一 
          if (!road.empty() && road.top() == start) {
              visited[road.top()] = false;
              steps--;
              road.pop();
          }
     }
}

int main() {
    memset(loc, 0, sizeof(loc));
    int value = 1;
    for (int i = 2; i <= 6; i++) {
        for (int j = 2; j <= 7; j++) {
            coors[value].x = i;
            coors[value].y = j;
            loc[i][j] = value++;
        }
    }
    
    int start;
    while (cin>>start&&start!=-1) {
          memset(visited, false, sizeof(visited));
          int steps = 0;
          stack<int> road;
          road.push(start);
          visited[road.top()] = true;
          search(road.top(), steps, road);
    }
    return 0;
}                                 
相關文章
相關標籤/搜索