POJ棋盘问题(kuangbin带你飞搜索专题)

题意:在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

Input
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
当为-1 -1时表示输入结束。
随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
 
题解:在n*n的棋盘上方k个问题,类似n皇后问题,但是又不完全相同,因为k<=n,并不是每一行都会放棋子,所以对于每一行都有两种选择:放棋子或者不放棋子。这也正是深搜的两个分支。我们可以从第一行开始向下搜索,如果某一列可以放置棋子,那么把这一列标记,保证以后搜索不再把棋子放置在这一列上。当找到k个放棋子的位置时,递归返回,把每一列的标记清除。保证棋子位置可以再次搜索寻找下一种放k个棋子的方案。
递归结束有两种情况:一种情况是从上往下每一行棋盘都搜索完毕,程序返回。另一种情况是找到k个放棋子的位置,找到一种解,程序不再向下执行,递归返回寻找新的方案。
#include<cstdio>
#include<cstring>
int n,k;
int ans;
char mp[10][10];
bool vis[10];//标记哪一列被使用
void dfs(int x,int cnt){
    if(cnt==k){
        ans++;
        return;
    }
    if(x==n){
        return;
    }
    //这一行可以放棋子
    for(int i=0;i<n;i++){
        //在可以放置棋子的前提下判断是否有可以放棋子的位置
        if(!vis[i] && mp[x][i]=='#'){
            vis[i]=true; //标记这一列已经放置棋子
            dfs(x+1,cnt+1);
            vis[i]=false;//递归返回时清除标记,保证能再次搜索这个位置
        }
    }
    //这一行不放棋子
    dfs(x+1,cnt);
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF){
        if(n==-1 && k==-1) break;
        //初始化变量
        ans=0;
        memset(mp,0,sizeof(mp));
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            scanf("%s",mp[i]);
        }
        dfs(0,0);//从第0行第0个元素开始搜索
        printf("%d\n",ans);
    }
    return 0;
}

写法二:

从当前行开始,搜索下面的每一行,在每一层递归中,都可以从当前行x的任意一行开始搜索,那么也代表着每一行可能放棋子,也可能不放棋子。(额,二层for循环的递归不知该怎么解释是好了,如果谁有更好的解释可以在下面评论)

理解二重for循环+递归

一重for循环加上递归可以搜到每一列,对于二重for循环,在递归的每一层程序中(每一层函数),可以任意选择每一行的棋盘。例如第一层递归程序,可以选择使用第1行、第2行、...第n行棋盘,第二层递归,可以选择第2、3...n行棋盘,第三层递归可以选择第3行、第4行、...、第n行棋盘。所以当每一层递归程序任意选择一行棋盘,这样就构成了搜索的所有选择。 (解法一的两个搜索分支也组成了所有的搜索选择)

void dfs(int x,int cnt){
    if(cnt==k){
        ans++;
        return;
    }
    for(int i=x;i<n;i++){
        for(int j=0;j<n;j++){
            if(!vis[j] && mp[i][j]=='#'){
                vis[j]=true;
                dfs(i+1,cnt+1);
                vis[j]=false;
            }
        }
    }
}

 

posted @ 2020-03-12 21:30  三行代码划江湖  阅读(350)  评论(0编辑  收藏  举报