棋盘问题(带条件的DFS)

本文介绍了一个特定的深度优先搜索(DFS)问题——在给定形状的棋盘上摆放棋子,要求任意两个棋子不在同一行或列。通过分析问题特点,采用DFS算法求解所有可能的摆放方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

棋盘问题(带条件的DFS)

题目

   在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放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

思路

   这是一道有条件的DFS(深度搜索)问题,题目所要求的数据量并不是很高,所以直接在满足条件的情况下深搜就好!

1.寻找条件

从题目中我们不难找出本题一共有5个限制条件:
1.棋盘的大小:n*n
2.棋子的数量:K个
3.下棋的位置:必须是在#上
4.下棋的位置:行上没有棋子
5.下棋的位置:列上没有棋子

2.应对限制条件

1.棋盘大小

   我们在初始化棋盘时,用一个二维数组来代表棋盘,在遍历棋盘时使用两个大小为n的for循环去遍历。

2.棋子的数量

   函数DFS()传入一个变量,表示棋子数量,模拟下棋的棋子变化,每下一次棋,棋子数-1,直到最后棋子数为0时结束这一轮下棋 (做为一种递归退出条件) ,同时也标志着一种可能性的增加

3.下棋的位置

   限制条件在#区域进行操作,将Vis设置为一个一维数组,表示这一列老子都占了,这就很巧妙的规避了一列有相同棋子的情况,而函数DFS()传入一个参数,表示所检查的当前行数,每次递归时从当前位置的下一行进行检查,这就很巧妙的规避了一行有相同棋子的问题。

代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
#include <unordered_map>
#include <vector>
#include <cmath>
#include<string.h>
#include <bits/stdc++.h> 
 
using namespace std;
 
#define LL long long
#define Ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
#define mem(a,b) memset(a,b,sizeof(a))
 
char Map[9][9]; //开一个二维数组代表N*N的棋盘
int vis[50]; //落一个子后,此子所在的一列全满,表示接下来的步骤不可在此列落
int n,k,ans;

void dfs(int m,int k){
    //棋子没了直接退出本次模拟,并且方案数++
    if(k==0){
        ans++;
        return ;
    }
    //两层循环为解决限制条件1
    for(int i=m;i<n;i++)
        for(int j=0;j<n;j++){
        if(Map[i][j]=='.'||vis[j]==1) continue; //有子不落,或者白不落
        else{
            vis[j]=1; //落一个子后,此子所在的一列全满,表示接下来的步骤不可在此列落
            dfs(i+1,k-1); //直接检查下一行,此行不检查保证此行只落一个子,并且棋子数-1
            vis[j]=0; //要进行下一轮的模拟了,把上一轮落下的棋子拿掉,这里是回溯的思想
        }
    }
}

int main(){
     while(scanf("%d%d",&n,&k) != EOF){
        if(n==-1&&k==-1)
            break;
        for(int i=0;i<n;i++)
            scanf("%s",&Map[i]);
        mem(vis,0);
        ans=0;
        dfs(0,k);
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值