POJ 1321——棋盘问题(DFS)

来源:互联网 发布:工作台设计作图软件 编辑:程序博客网 时间:2024/06/08 03:43
棋盘问题
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 50420 Accepted: 24427

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

这道题乍一看真的跟N皇后问题很像,也是在棋盘上摆棋子,需要满足同一行、同一列只能有一个。

不同的是,棋盘有了限制,不是所有位置都可以放。

一开始我的思路是这样的,先找到第一个能放棋子的位置,开始进行dfs

用两个数组line,row分别作为标记,记录改行或该列有没有被放棋子。

然后。。中间出了一些错误以后。

最后发现每次搜索要从当前能放位置的下一行开始循环找能放的地方。

这样才不会重复计算。

调了良久以后,最后写出来个125ms的。

后经思考(又是看了题解),发现不用记录每一行的访问与否,每次只要从下一行开始搜索就能保证不会有同一行两个棋子。

此外,每次搜索分两种情况,一种是这一行放棋子,另一种是不放。这样就能得出结果。

此题还可以剪枝,如果剩下的行数比当前棋子数少的话,就return 成功优化到16ms。

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <queue>#include <cctype>#define N 10010using namespace std;int n,m,ans;char M[10][10];bool row[10];void dfs(int i,int cnt){    if(i>n&&cnt!=0)return;    if(cnt>n-i)return ;//剪枝,如果剩余的棋子比行数多的话return    if(cnt==0)    {        ans++;        return ;    }    for(int j=0;j<n;j++)    {        if(row[j]==0&&M[i][j]=='#')        {            row[j]=1;            M[i][j]='&';            dfs(i+1,cnt-1);            M[i][j]='#';            row[j]=0;        }    }    dfs(i+1,cnt);}int main(){    //freopen("C:\\Users\\CQJ3360\\Desktop\\in.txt","r",stdin);    while(cin>>n>>m)    {        if(n==-1&&m==-1)break;        cin.get();        ans=0;      //  memset(line,0,10);        memset(row,0,10);        for(int i=0; i<n; i++)            cin>>M[i];        dfs(0,m);        cout<<ans<<endl;    }    return 0;}


原创粉丝点击