poj1321

来源:互联网 发布:战争程序员的漫画 编辑:程序博客网 时间:2024/05/16 11:05

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
----------------------------------------8皇后的变种-----------------------------------------------------------
我通过枚举行,加上判断是否能放在这一列。因为n<=8,所以可以采用一个int类型的变量利用位运算来存储状态。然后再递归实现。
2个简单的剪枝:当已经摆放的棋子个数加上所剩的行数小于要求摆放的棋子个数时,剪枝;
当已经摆放的棋子个数加上所剩行中所有的棋子个数小于要求摆放的棋子个数时,剪枝;
通过预处理,计算出前i行的棋子总数(num[i]);
  1. #include<iostream>
  2. using namespace std;
  3. int n,m,sum,num[10];
  4. char chess[10][10];
  5. void init( )
  6. {
  7.     int i,j;
  8.     memset(num,0,sizeof(num));
  9.     for ( i=0 ; i<n ; i++ )
  10.     {
  11.         scanf("%s",chess[i]);
  12.         for ( j=0 ; j<n ; j++ )
  13.             if ( chess[i][j]=='#' )
  14.                 num[i+1]++;
  15.         num[i+1]+=num[i];
  16.     }
  17.     sum=0;
  18. }
  19. void solve ( int line , int cnt , int mark )
  20. {
  21.     int i;
  22.     if ( line==n )
  23.     {
  24.         if ( cnt==m )
  25.             sum++;
  26.         return ;
  27.     }
  28.     if ( cnt+num[n]-num[line]<m || n-line+1+cnt<m )
  29.         return ;
  30.     for ( i=0 ; i<n ; i++ )
  31.         if ( chess[line][i]=='#' && ((mark>>i)&1)==0 )
  32.             solve(line+1,cnt+1,mark|(1<<i));
  33.     solve(line+1,cnt,mark);
  34. }
  35. int main ( )
  36. {
  37.     int i,j;
  38.     while( scanf("%d%d",&n,&m) && m!=-1 && n!=-1 )
  39.     {
  40.         init();
  41.         for ( i=0 ; i<n ; i++ )
  42.             for ( j=0 ; j<n ; j++ )
  43.                 if ( chess[i][j]=='#' )
  44.                     solve(i+1,1,1<<j);
  45.         printf("%d/n",sum);
  46.     }
  47. }

原创粉丝点击