POJ-1321-棋盘问题

K - 棋盘问题
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u
Submit

Status

Practice

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

深度搜索,递归解决
递归终止条件:棋子已下完,搜索越界,当前搜索坐标已被访问过。
满足以上任意条件就可以结束当前结点.

搜索时可能出现,棋子下完,棋盘仍然有剩余的情况,此时要接着下一行继续搜索,这样才会得出最多种方法

还有递归的时候,千万别一层层的想那么深,那只会让人抓狂,毕竟人脑不是CPU。
实现递归时,人脑的思维只需要着重实现一层,再往下交给计算机就行。

代码

#include<stdio.h>
#include<string.h>
#include<string>
#include<stack>
#include<queue>
#include<math.h>
#include<limits.h>
//#include<malloc.h>//加上这个头文件会编译错误,原因不明
#include<iostream>
#include<algorithm>
using namespace std;
char map[10][10];//接收地图
int visited[10];//当前列已访问标记为0,未访问标记为1
int sum;//记录方法总数
int n;//地图大小
int k;//棋子数量
void DFS(int line,int num)//传入当前行和已用棋子数
{
    if(num==k)//如果棋子用完
    {
        sum++;//方法总数加一
        return;//结束当前递归
    }
    if(line>=n)//如果搜索越界
        return;//结束搜索
    for(int i=0;i<n;i++)//棋子没用完,搜索没越界,那就继续搜索
    {
        if(visited[i]==1&&map[line][i]=='#')//坐标可被访问且未被访问过
        {
            visited[i]=0;//先标记当前坐标为已访问,因为后面还要递归搜索
            DFS(line+1,num+1);//行数加一,已用棋子数加一,继续搜索
            visited[i]=1;//完成一遍后,vsited全部标记为未访问,准备为寻找下一种方法继续标记
        }
    }
    DFS(line+1,num);//如果未搜索完一遍,棋子就用完了,那就接着下一行搜索新的方式,防止遗漏
    return;
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        if(n==-1&&k==-1)
            break;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                cin>>map[i][j];//之前用scanf接收,结果异常,改成cin就没事了,未解之谜。。。。
            }
        }
        sum=0;//初始化方法总数
        for(int i=0;i<10;i++)//当前列未访问标记为1
            visited[i]=1;
        //memset(visited,1,sizeof(visited));//这种初始化方式好像不对,把它注释掉了
        DFS(0,0);//从第0行开始搜索,已用棋子数为0
        printf("%d\n",sum);
    }
    return 0;
}

搜索问题确实有一定的套路可循

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值