POJ1321 棋盘问题 —— DFS回溯

来源:互联网 发布:c语言二级考试真题 编辑:程序博客网 时间:2024/05/17 02:06

题目链接: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

21

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






原创粉丝点击