1. 程式人生 > >【 OJ 】 HDOJ1045 18年12月8日11:41 [ 39 ]

【 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;
}