POJ - 1321 棋盘问题 (DFS 回溯)

题目链接:

http://poj.org/problem?id=1321


思路:

对每行进行递归,用数组来记录每列是否有放置棋子。


对于每行,先对其各列进行一次判断:若该列是棋盘,且该列没有棋子,则在该位置放置棋子,调用DFS递归以后,重置该列的标记(回溯思想),继续判断别的列


此外,由于该题可能存在 k < n 的情况,因而,也有可能存在这一情况:调用DFS函数的这一行,暂时不放棋子(因为行数可能是大于棋子数的,一行不放棋子,也是可能存在,但我们在上面的循环中,没有分析的情况),因而,在循环完这一行的所有列以后,还要再加上这一种情况,也即  DFS(step, row + 1);


坑点:

这题莫名其妙崩了以后,找错误找了很久,才发现:

string类数组是不可以用memset函数来清零的(不仅仅是string类数组,所有类数组都不可以)

细节可见:

http://blog.csdn.net/wangshubo1989/article/details/50300813

https://www.cnblogs.com/Thinkingcao/p/8043884.html


代码:

#include 
#include 
#include 
#include 
#define Clear(x, y) memset(x, y, sizeof(x))
using namespace std;
const int N = 10;
int n, k, ans;
string str[N];
int vis[N];

// 按行进行DFS
void DFS(int step, int row)
{
	if (step == k) //已经走到第k步了,说明多出一种走法
	{
		ans++;
		return;
	}

	if (row >= n)
	{
		return; //超过指定维度,则结束DFS
	}

	//遍历这一行的每一列,对可以放棋子的地方,先放棋子;然后回溯,以继续循环判断这一行的其他列能否放棋子,若能,继续 DFS
	for (int i = 0; i < n; i++)
	{
		if (!vis[i] && str[row][i] == '#')
		{
			vis[i] = 1;
			DFS(step +1, row + 1); //对这一行放棋子的情况进行递归
			vis[i] = 0; //回溯法,标记重置为初始值
		}
	}
	DFS(step, row + 1);
	/*
	这步的含义是,因为有可能存在:所放的棋子数 k < n,因而对每一行,它可以放棋子递归,再回溯,继续判断不放棋子的情况,但是,它也可以直接确定,这一行不放棋子,因为行数是有可能比棋子数多的,所以我们也可以直接这行不放,以后的行再放棋子(这是为了特别处理 k < n 这一种比较特殊的情况)
	*/
}
int main()
{
	while (cin >> n >> k)
	{
		if (n == -1 && k == -1) break;
		
		getchar();
//		memset(str, 0, sizeof(str));
		memset(vis, 0, sizeof(vis));
		
		for (int i = 0; i < n; i++)
			getline(cin, str[i]);

		ans = 0;
		DFS(0, 0);
		cout << ans << endl;
	}
	return 0;
}





你可能感兴趣的:(POJ)