天天看點

棋盤問題(poj 1321)

問題描述:

在一個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有差別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請程式設計求解對于給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案C。

輸入:

輸入含有多組測試資料。

每組資料的第一行是兩個正整數,n k,用一個空格隔開,表示了将在一個n*n的矩陣内描述棋盤,以及擺放棋子的數目。 n <= 8 , k <= n

當為-1 -1時表示輸入結束。

随後的n行描述了棋盤的形狀:每行有n個字元,其中 # 表示棋盤區域, . 表示空白區域(資料保證不出現多餘的空白行或者空白列)。

輸出:

對于每一組資料,給出一行輸出,輸出擺放的方案數目C (資料保證C<2^31)。

樣例輸入:

2 1

#.

.#

4 4

…#

…#.

.#…

#…

-1 -1

樣例輸出:

2

1

題目解析:見代碼注釋。

代碼:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>

using namespace std;
int n, k;
char a[10][10];
int visited[10];//visited數組記錄在前h-1行第幾列已經放入棋子了
int cont = 0;//cont代表種數
int way = 0;

void dfs(int h)//h代表行數   way代表選擇放入棋子的個數
{
    if (way == k)//當放入的棋子數等于給定需要放入的棋子數時   方案數加1
    {
        cont++;
        return;
    }
    if (h >= n)//當所搜尋的行數大于棋盤時   直接傳回
        return;
    for (int i = 0; i < n; i++)//在第h行中從第一個位置開始列舉
    {
        if (!visited[i] && a[h][i] == '#')//目前h-1行中第i列中已經放入了棋子  那麼第h行就不用放了  因為棋子不能放在同一行 同一列
        {
            visited[i] = 1;
            way++;
            dfs(h + 1);
            visited[i] = 0;//還原  假如第0行有兩個#  當從第0行的第一個#開始往下走時,假設第2行中有且隻有一個#,并且不與第一行中的任意一個在同一列,那麼在往下
            way--;//走時就會把這個#标記  當遞歸傳回到第一行第一個#時  i會++  到第一行的第2個#  函數繼續會繼續往下走 ,到達第2行的那個#,因為在第一行第一個#那條路徑中
            //已經走過了第2行的那個#(因為第2行隻有一個#并且這個#所在的列數不與第一行兩個#重合),如果不把第一次走過第二行的#的标記消除  那麼這次路徑就不會再過第二行的
            //這個#  那麼可選路徑少了  肯定不對了
        }
    }
    dfs(h + 1); //若改行沒有可以放的位置那麼就找下一行
}

int main() {
    while (cin >> n >> k) {
        if (n == -1 && k == -1)
            break;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                cin >> a[i][j];
        dfs(0);
        cout << cont << endl;
        memset(visited, 0, sizeof(visited));
        cont = 0;
        way = 0;
    }

}
           

繼續閱讀