kuangbin带你飞 A 搜索 ——棋盘问题

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

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

题解:
这道题用深搜,用回溯法,2^n的复杂度,是不能过的,这道题需要剪枝。
写题目,要分析问题的本质,

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
int n,k;
int ans=0;
char a[9][9];
int couns=0;
struct note
{
    int x,y;
} p[65];

bool line[10];用数组标记
void dfs(int row,int c)row用来标记第几行  c用来表示已经多少个棋子
{
    if(c==k)
    {
        ans++;
        return ;
    }
    for(int i=row+1;i<n;i++){
我这里一开始是forint i=0;i<n;i++)for(int j=0;j<n;j++) 
我这里就是没有分析清楚,要求摆放时任意的两个棋子不能放在棋盘  中的同一行或者同一列,其实这里如果这一行已经放过,应该直接下一行,而不是对这一行继续进行判断,这里的判断是多余的
        for(int j=0;j<n;j++){
            if(a[i][j]=='#'&&line[j]==false){
                line[j]=true;
                dfs(i,c+1);
                line[j]=false;
            }
        }
    }
}

int main()
{
    #ifdef ONLINE_JUDGE
    #else
    freopen("poj1321.txt","r",stdin);
    #endif // ONLINE_JUDGE
    while(cin>>n>>k&&(n+k)>0)
    {
        memset(line,false,sizeof(line));
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
            {
                cin>>a[i][j];字符建议用cin输入,比较方便,一般这种题目输入也不会很大
            }
        }
        ans=0;
        dfs(-1,0);
        cout<<ans<<endl;
    }
    return 0;
}
// if(n-row+c<k){
// return ;
// }
// int b[10];
// int coun=0,nums=0;
// for(int i=0;i<n;i++){
// if(line[i]==false){
// b[coun++]=i;
// nums++;
// }
// }
// if(nums+c<k){
// return ;
// }

错误代码·1:

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
int n,k;
int ans=0;
char a[9][9];
bool solve()   在搜索时不要单独检验是不是同一行  同一列这种问题  非常浪费时间
{
    int numc=0,numl=0;
    for(int i=0; i<n; i++)
    {
        numc=numl=0;
        for(int j=0; j<n; j++)两层循环  大量耗费时间
        {
            if(a[i][j]=='#')
            {
                numc++;
            }
            if(a[j][i]=='#')
            {
                numl++;
            }
        }
        if(numc>1||numl>1)
        {
            return false;
        }
    }
    return true;
}
void dfs(int c)
{    //cout<<"c="<<c<<endl;
    if(c==k)
    {
        //cout<<"k="<<k<<endl;
        if(solve())
        {
            ans++;
        }
        return ;
    }

    for(int i=0; i<n; i++)这里的循环0-》n 复杂度太高
    {
        for(int j=0; j<n; j++)
        {
            if(a[i][j]=='#')
            {
                a[i][j]='.';
                dfs(c-1);
                a[i][j]='#';
            }
        }
    }
}

int main()
{
    while(cin>>n>>k&&(n+k)>0)
    {
        int u=0;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<n; j++)
            {
                cin>>a[i][j];
                if(a[i][j]=='#'){
                    u++;
                }
            }
        }
        ans=0;
        dfs(u);
        cout<<ans<<endl;
    }
    return 0;
}

在写搜索的时候,我们应尽量避免“检验”,也就是说,我们搜索的每一步,都应该离目标越来越近,我们要多分析题目,利用题目条件剪枝,同时运用数组标记,避免重负搜索

你可能感兴趣的:(搜索)