天天看點

poj1321

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