棋盤問題:任意兩棋子不能同行同列(深搜dfs)

Description
在一個給定形狀的棋盤(形狀可能是不規則的)上面擺放棋子,棋子沒有區別。
要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列。請編程求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案C。
Input
輸入含有多組測試數據。

每組數據的第一行是兩個正整數,n,k,用一個空格隔開,表示了將在一個n∗n的矩陣內描述棋盤,以及擺放棋子的數目。

當爲−1 −1時表示輸入結束。

隨後的n行描述了棋盤的形狀:每行有n個字符,其中 # 表示棋盤區域, . 表示空白區域(數據保證不出現多餘的空白行或者空白列)。
Output
對於每一組數據,給出一行輸出,輸出擺放的方案數目C。
Sample Input 1
2 1
#.
.#
4 4
…#
…#.
.#…
#…
-1 -1
Sample Output 1
2
1
Hint
n<=8,k<=n
數據保證C <2^31
Time Limit
1000MS
Memory Limit
256MB

分析:題意爲求所有棋子擺放方案數,可知此題用深搜。撰寫搜索代碼的關鍵,在於理清楚搜索的單位,即空間狀態——能區分出每個結點的因素、進行搜索的邏輯在數據上的體現。此題中空間狀態不妨設爲:擺放在棋盤第幾行、還有幾個棋子未擺放。同時,此題的特別之處在於棋盤上的一行或多行可以不擺棋子,這時的空間狀態只變化行數,不變化剩餘棋子數。

參考代碼:

#include<stdio.h>

int n,k;//棋盤尺寸,棋子數目
int ans;//擺放方案數
char map[9][10];//描述棋盤的內容
bool vis[9];//記錄棋盤裏已經被佔用的列
//當前擺放棋盤第幾行,當前還有幾個棋子未擺放
void dfs(int now,int last)
{
    if(last==0){//沒有剩餘棋子,都擺放完了
        ans++;//找到一種擺放方案
        return;
    }
    if(now>n){//當前方案不合法,回退,重新搜索
        return;
    }
    //按列枚舉
    for(int j=1;j<=n;j++)
    {//是空白區域或者已經被佔用
        if(map[now][j]=='.'||vis[j]) continue;
        vis[j]=true;//標記
        dfs(now+1,last-1);//擺下一行,棋子數減1
        vis[j]=false;//回溯
    }
    //這一行沒有擺棋子,到下一行去擺
    dfs(now+1,last);
    return;
}

int main()
{
    while(1)
    {
        scanf("%d%d",&n,&k);
        if(n==-1&&k==-1) break;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",&map[i][1]);
        }
        ans=0;//答案清零
        for(int i=0;i<9;i++)
        {//標記數組也清零
            vis[i]=0;
        }
        dfs(1,k);//開始搜索
        printf("%d\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章