POJ1321 棋盘问题—— DFS回溯

xiaoxiao2021-02-28  59

题目链接:http://poj.org/problem?id=1321

棋盘问题 Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 50263 Accepted: 24352

Description

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

Input

输入含有多组测试数据。  每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n  当为-1 -1时表示输入结束。  随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。 

Output

对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

Sample Input

2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1

Sample Output

2 1

Source

蔡错@pku

题解:

类似于八皇后问题。

由于题目要求放k个,不像八皇后那样固定了8个,所以在一开始时不知道怎样处理“k个”。即如果实际能放的位置比k要大时该怎么处理

一开始是想:在能够放的地方,执行两种操作,放和不放。但是却会出现重复,因为对于一行,不放的位置可以是多个,这就有了多种情况,但实际上这多种情况都是一样的,因为对于接下来的行,所呈现的状态是一样的。

正确的操作是:把操作对象从“一个”改为“一行”。对于每一行,有放和不放两种操作,如果不放,则直接跳过;如果放,则再决定放在哪个位置。

代码如下:

#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <string> #include <set> #define ms(a,b) memset((a),(b),sizeof((a))) using namespace std; typedef long long LL; const int INF = 2e9; const LL LNF = 9e18; const int MOD = 1e9+7; const int MAXN = 8+10; int n, k, ans; char m[MAXN][MAXN]; int col[MAXN]; void dfs(int dep, int t) { if(dep==n+1) //到达末时,如果刚好放了k个,则计数器+1 { if(t==k) ans++; return; } dfs(dep+1, t); //这一行不放 for(int i = 1; i<=n; i++) //这一行放 { if(m[dep][i]=='#' && col[i]==0 && t<k ) //t<k为剪枝 { col[i] = 1; dfs(dep+1, t+1); col[i] = 0; } } //以下为错误的思想 // for(int i = 1; i<=n; i++) // { // if(m[dep][i]=='#' && col[i]==0 ) // { // dfs(dep+1, t); //会出现重复 // col[i] = 1; // dfs(dep+1, t+1); // col[i] = 0; // } // } } int main() { while(scanf("%d%d",&n,&k)) { if(n==-1 && k==-1) break; ms(col,0); ans = 0; for(int i = 1; i<=n; i++) scanf("%s", m[i]+1); dfs(1, 0); cout<< ans <<endl; } }

转载请注明原文地址: https://www.6miu.com/read-69993.html

最新回复(0)