1. 程式人生 > 實用技巧 >棋盤問題

棋盤問題

棋盤問題

POJ - 1321

(這麼簡單的板子題都能卡,太弱了md)

一開始用的複雜度能高到\(O(n!)\)的DFS...後面參考了一下題解,算是懂問題出在哪了。

那個\(O(n!)\)的方法是這樣想的,整個遍歷一遍棋盤,找到適合的就做標記,回溯...我自己看著是沒什麼問題,不過最後答案就是標答的\(k!\)倍...重複計算太多了

看了一下題解,問題在這:不是遍歷整個棋盤,而是遍歷到下一行。因為棋子不能放於同一列,這一列放完了就在下一列DFS,因此不會有重複的情況。

接下來的程式碼用的是從上到下的DFS,按理論來說,從左到右,從下到上應該都行吧。

//#include <bits/stdc++.h>
#include <cstring>
#include <iostream>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

int mod = 9973;
const int INF = 0x3f3f3f3;
const int maxn = 2e2 + 10;

int n, k;
char Map[10][10];
int xx[10], yy[10];
ll res = 0;

void dfs(int y, int num)
{
	if (num == 0)	//棋子放完,答案+1
	{
		res++;
		return;
	}
	for (int i = y; i < n; i++)	//就是這樣,從y開始,而不是0
	{
		for (int j = 0; j < n; j++)
		{
			if (Map[i][j] == '#' && (!xx[j]))//xx是記錄列是否有重複情況的
			{
				xx[j] = 1;
				dfs(i + 1, num - 1);//DFS下一行,棋子少一個
				xx[j] = 0;//回溯
			}
		}
	}
}
int main()
{
	while (cin >> n >> k)
	{
		res = 0;
		memset(xx, 0, sizeof(xx));
		if (n == -1)
			break;
		for (int i = 0; i < n; i++)
		{
			cin >> Map[i];
		}
		dfs(0, k);	//從第0行開始,一開始有k個棋子要放
		cout << res << endl;
	}
	return 0;
}