海域, 冰山, 战舰

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/windywo/article/details/47805779

时间限制: 1 Sec
内存限制: 128 MB
提交: 33
解决: 11
[提交][状态][讨论版]

题目描述
给出一个n * n的海洋,#代表海域,.代表冰山,要在海域中放置k个战舰,战舰会攻击同一行同一列的其他战舰,所以同一行同一列不能放置其他战舰,问摆放战舰的方案数目C有多少种(数据保证C<2^31)。

输入
输入含有多组测试数据。
每组数据的第一行是两个正整数,n k,(n <= 8, k <= n)

随后的n行描述了的海洋的形状:每行有n个字符,其中 # 表示海域, . 表示冰山

输出
对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。

样例输入
2 1
#.
.#
4 4
…#
..#.
.#..
#…
样例输出
2
1

题意识先输入n表示n*n的海域,然后输入k表示需要放置k艘战舰,(k<=n),‘#’表示海域可以放战舰,‘.’表示不可以,且同一行同一列不能同时放置战舰,求可以有多少种放置方式

这道题与n皇后相似,都是说同一行同一列不能放置,但此题又比n皇后限制条件多一点,首先能放置的位置是固定的,某些点一定不能放,其次该题不似n皇后那样必须要放置n个,而是输入的k个,但大体上差不多

对于要求多少种方式的问题,若数据较小,便用dfs解决。

#include<cstdio>
#include<cstring>
int n,k,sum,flag;
char map[10][10];//记录地图
int w[10];//标记是否访问过
int can(int a,int b)
{
    if(!w[b]&&map[a][b]=='#'&&a>=0&&a<n)
        return 1;//return 1 的情况不能分开写  
    return 0;//在if的情况下return 0就会出错 
}
void dfs(int a)//a表示第a行
{
    if(flag>=k)//不要在这里用个大括号写使flag=0 
        sum++;//方式
    else if(a==n)//绝对不能少!! 
        return ;
    else
    {
        for(int i=0;i<n;i++)//i表示第a行的第i个
        {
            if(can(a,i))
            {
                w[i]=1;
                flag++;//记录已经放置好了多少艘战舰
                dfs(a+1);//访问下一行
                w[i]=0;//还原
                flag--;//不要忘 ,很重要
            }
        }
        dfs(a+1);//若第a行没有放或者不能放,就要从a+1行访问
    }       
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        int i;
        sum=0;
        flag=0;
        memset(w,0,sizeof(w));
        for(i=0;i<n;i++)
            scanf("%s",&map[i]);
        dfs(0);//从第0行开始访问
        printf("%d\n",sum);     
    }   
    return 0;
}
#include<cstdio>
#include<cstring>
int n,k,sum;
char map[10][10];
int w[10];
int can(int a,int b)
{
    if(a<0||a>=n||b<0||b>=n)//越界
        return 0;
    if(w[b]||map[a][b]=='.')//访问过或者不能放置
        return 0;
    return 1;
}
void dfs(int a,int b)//表示放置到了第a行,已经放置了b个
{
    if(b==k)//放置完k个表示已经达到目标,方式sum++
        sum++;
    else if(a==n)//地图已经访问完了,结束
        return ;
    else
    {
        for(int i=0;i<n;i++)
        {
            if(!w[i]&&map[a][i]=='#')//为什么一定要写成立的情况,写不成立的情况就会WA 
            //第a行没有标记过并且第i列也没有被标记
            {
                w[i]=1;
                dfs(a+1,b+1);
                w[i]=0;
            }
        }
        dfs(a+1,b);
    }

}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        sum=0;
        memset(w,0,sizeof(w));//w[i]表示第i列是否被标记过
        for(int i=0;i<n;i++)
            scanf("%s",&map[i]);
        dfs(0,0);
        printf("%d\n",sum);     
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/windywo/article/details/47805779