zoukankan      html  css  js  c++  java
  • 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
    ",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;
                }
            }
        }
    }
  • 相关阅读:
    [置顶] 文件批量重命名(工具)
    zookeeper源码分析之三客户端发送请求流程
    java set转list,数组与list的转换
    分布式电子邮件系统设计--转载
    redis 模糊删除实现
    eclipse 使用jetty调试时,加依赖工程的源码调试方法
    社交产品后端架构设计--转载
    solr服务器的查询过程
    What is corresponding Cron expression to fire in every X seconds, where X > 60? --转载
    zookeeper源码分析之二客户端启动
  • 原文地址:https://www.cnblogs.com/mld-code-life/p/12482865.html
Copyright © 2011-2022 走看看