【 OJ 】 HDOJ1045 18年12月8日11:41 [ 39 ]
有些事情耽誤了,所以最近沒寫程式碼,此題我開始的思路還算正常,後來跑偏了....開始拿到這題第一反應就是八皇后問題,遞迴
DFS,因為這題有X塊限制,所以我的最初思路是:先和八皇后類似先在 . 塊中放能放的,X塊可以遮擋補充的地方先不考慮,當 . 塊的最後一層放完後,開始考慮X塊可以放的,一個X塊可以遮擋四個方向...因此四向搜尋(先前已經記錄 行 列情況)X塊列中看行的合法情況,行中看列的合法情況....後來發現其實這個思路是有問題的...不好實現的地方在於:
X快可以遮擋4個方向(如:【.】在【X】南可以擋住北方的子彈),假設一共有n個X快,我每次拿到一個X塊(很容易一個for迴圈)此時有2種:第1種:我把當前的X塊可以擋住的四個方向可以放的【.】全部放進去,然後取後面X塊繼續這麼做(顯然不對),第2種:我順序檢測X塊四周,每當遇到一個方向能放【.】塊就遞迴進去做下一個X塊,重複上述步驟(顯然也不對)
這2種情況無論怎麼做都不對,因為結果很顯然可以想象,假設第一個X塊我擋了2個方向,第二個擋了1個,無論第一種還是第二種的迴圈都做不出這種情況....不可能說我第二種一路找找到最後一個X塊發現沒法放了,在回到第一個X快從上次檢查的下一個方向繼續到最後一個X塊...當然X塊從1到結束至多迴圈4次(理論上可以這麼做,現實是怎麼實現好煩.....)
所以開始這個思路算是壯烈犧牲了.
參考思路:https://blog.csdn.net/cr496352127/article/details/79640988
網上看了別人的思路....簡潔明瞭乾淨....這題最多4層,最多16個元素,不論【.】或者【X】每個元素2種可能【放/不放】,從第1個元素搜尋遍歷到最後一個元素,每次遇到【.】我就檢查他是否合法,如果合法我就去遞迴下一個元素,並且當前標記放(遞迴結束說明放的所有情況看完了,剩下就是當前【.】塊不放的,因此遞迴下個元素,當前標記不放,此操作和遇到X塊操作一致)
檢查:
因為此題是順序遍歷元素因此元素後面的還沒有放,本來X塊可以擋4個方向,但是由於後面的沒放,只需要在二維圖中考慮左上是否有【.】即可
# include<iostream> using namespace std; int n,max; char map[4][4]; bool check(int index) { int x, y; x = index / n; y = index%n; for (int i = x-1; i >= 0; i--) { if (map[i][y] == 'X')break; if (map[i][y] == 'V')return false; }//列檢查 for (int j = y-1; y >= 0; y--) { if (map[x][j] == 'X')break; if (map[x][j] == 'V')return false; }//行檢查 return true; } void DFS(int index,int num) { if (index == n*n) { if(num>max) max = num; return; } int x, y; x = index / n; y = index%n; if (map[x][y] == '.'&&check(index)) { map[x][y] = 'V';//標記為訪問 DFS(index + 1, num + 1); map[x][y] = '.'; } DFS(index + 1, num); } int main(void) { int i, j; cin >> n; while (n) { max = 0; for (i = 0; i < n; i++) for (j = 0; j < n; j++) cin >> map[i][j];//錄入地圖 DFS(0, 0); cout << max << endl; cin >> n; } system ("pause"); return 0; }