棋盘问题

L - 棋盘问题

 

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


题意及要求:给了我们一个棋盘,其中'#'代表能放棋子的地方'.'则表示不能放棋子的地方,然后要把k个棋子放入棋盘,使得每行每列有且仅有一个棋子.求有多少种这样的方法满足题意.


分析:需要得出方法数,每次这个方法从棋盘放置中得出,并且方法可行性也从棋盘放置这里得出,那么要怎么放置呢.

从左上角到右下角每个都试一试,如果使得k个棋子刚好放下,并且每行每列有且仅有一个棋子,那么方法数就+1;


那么就用dfs()了,那么dfs(参数)  参数是什么?

来分析一下,从左上角到右下角,放置棋子时 改变的自然就是k  棋子的个数.

同时,左上角到右下角变化的时候,行数也在改变.当然列数也在改变.还有就是方法数.

但,当且仅当满足时,方法数+1.所以不用后退继续寻找.

那么现在就是三个变量,行数,列数和棋子个数.

那么要怎么处理呢.


究竟要怎么搜索.

双层foe循环,从左上角到右下角.那么!!!,并且每行每列有且仅有一个棋子 这个要求要怎么处理.

放置一个棋子,那么那一列或者一行都无法再放置.如果可放置,那么vis=0;反之vis=1.

那么vis如果要用二维的,处理起来会有点麻烦.

所以要用一个巧妙的办法

我们从左上角移到右下角,行数变化了,因为有且仅有一个棋子,那么行数自上而下,也不用做什么处理.所以只要考虑列数,那么我们用vis存储列数.


此时列数已经有vis来控制,那么原来的三个参数自然就只剩两个了.


下面就上代码吧,千万句话来解释也不如一句代码.

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
int n,k,ans;
string s[100];
int vis[100];
void dfs(int row,int kk)
{
    if(kk==0)
    {
        ans+=1;
        return ;
    }
    for(int i=row;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(s[i][j]=='.'||vis[j]==1) continue;
            vis[j]=1;
            dfs(i+1,kk-1);
            vis[j]=0;
        }
    }
}
int main()
{
    while(cin>>n>>k)
    {
        if(n==-1&&k==-1)    break;

        ans=0;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<10;i++)
            s[i].clear();

        for(int i=0;i<n;i++)
        {
            getchar();
            cin>>s[i];
        }

        dfs(0,k);

        cout<<ans<<endl;
    }
}


ps:2018年4月10日 13:05:08 

昨晚第二次做这个题目,没有仔细思考,直接敲代码,以至于后来全是bug,然后边看博客边找自己的bug.

记得第一次做这个题目的时候也是这样.

果然,做个每个题目,不管简单还是难,都一定要给自己一点思考时间,要有自己的思维,否则就算此次做出来了,下次换汤不换药的随便改一改,就不会了.

因此不能在这么一味追求速度了,也要保证质量.!!!

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值