Fire Net

题目链接:

https://vjudge.net/contest/345248#problem/K

题面:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

翻译:

假设我们有一个街道笔直的方形城市。城市地图是一块有n行n列的正方形板,每一行代表一条街道或一堵墙。
碉堡是一个小城堡,有四个开口可以射击。这四个开口分别面向北、东、南和西。每个开口都会有一把机枪射击。
在这里,我们假设一颗子弹是如此强大,它可以跑过任何距离,摧毁一个碉堡在其途中。另一方面,墙是如此坚固,可以阻止子弹。
目标是在一个城市里尽可能多地安置碉堡,这样就不会有两个碉堡互相残杀。如果地图中没有两个碉堡位于同一水平行或垂直列上,则碉堡的配置是合法的,除非至少有一面墙将它们隔开。在这个问题中,我们将考虑小的方形城市(最多4x4个),这些城市的墙壁中子弹无法穿过。
下图显示了同一块板的五张图片。第一张图为空板,第二、三张图为合法配置,第四、五张图为非法配置。对于这个委员会,在法律配置中碉堡的最大数量是5;第二张图片显示了一种方式,但是还有其他几种方式。
你的任务是写一个程序,给定一个地图的描述,计算在法律配置中可以放置在城市中的碉堡的最大数量。

输入:
输入文件包含一个或多个映射描述,后跟一行数字0,表示文件结束。每个地图描述以包含正整数n(城市大小)的行开始;n最多为4。接下来的n行分别描述地图的一行,其中“.”表示开放空间,大写“X”表示墙。输入文件中没有空格。

输出:
对于每一个测试用例,输出一行,其中包含可以以合法配置放置在城市中的最大数量的碉堡。

思路:

这道题目就是要在n*n的方阵中找到能够放置的最大碉堡数目,而碉堡的安置要求是同一行或者同一列的两个碉堡之间必须需要墙隔开,否则就不可以放置,我们就是需要判断我们放置的时候是否满足需求,我们可以这样子想,当我们放置了一个碉堡时,我们可以开始查看位与这个碉堡的同一行和同一列的位置中,如果没有一堵墙,那么这一行和这一列都无法在按照碉堡了,如果查找到了墙,那么就意味着在与放置碉堡的同一侧的位置的其他地方不能放碉堡,而位于墙的另一侧还可以放碉堡,我们就可以通过判断,来把不能放碉堡的位置继续标记,能放的继续让它发,这样子就可以解决这道题目。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include<cmath>
using namespace std;
char map[121][121];
int n;
int ans;
bool check(int x, int y)//检查是否在这个位置放置碉堡
{
    bool f = true;//先把它定义为真
    for(int i=x; i>=0; i--)//如果从这个点开始向左查找
    {
        if(map[i][y]=='X')//如果出现了墙,我们就可以停止循环
            break;
        else if(map[i][y]=='a')//如果出现了一座碉堡,那么这个位置与这个碉堡之间没有墙来隔开就无法放置碉堡,所以再标记为假,并且直接跳出循环
        {
            f = false;
            break;
        }
    }
    for(int j=y; j>=0; j--)//这个是判断y轴,与上面x轴的基本一模一样
    {
        if(map[x][j]=='X')
            break;
        else if(map[x][j]=='a')
        {
            f = false;
            break;
        }
    }
    return f;//最后返回f的真假,从而来确定是否可以放置碉堡
}
void dfs(int point, int sum)
{
    int x = point / n;//这是一个用point来表示x,y的方法,我们每次point加1,就是向y轴移动一格,移动到边界时,就又返回到第二行的第一个,从而达到遍历每个点的作用。
    int y = point % n;
    if(point==n*n)//当point为n*n时就代表此时已经把所有点都遍历完了,就直接来查找放置碉堡的最大值
    {
        if(sum>ans)
            ans = sum;
        return ;
    }
    if(map[x][y]=='.'&&check(x, y))//如果中国点为草地,并且可以放置
    {
        map[x][y] = 'a';//就把放置了碉堡的点标记为a
        dfs(point+1, sum+1);//接着下一个点继续查找,并且碉堡的数量加1
        map[x][y] = '.';//之后再把碉堡的点恢复,达到回溯的作用
    }
    dfs(point+1, sum);//如果不能放置我们就继续查找下一个点能不能放置
}
int main()
{
    while(scanf("%d", &n)!=EOF)
    {
        if(n==0)
            break;//如果n等于0就跳出循环
        ans = 0;//把ans最初赋值为0
        for(int i=0; i<n; i++)
            scanf("%s", map[i]);
        dfs(0, 0);//从第一个开始查找
        printf("%d\n", ans);//输出最后的最大值
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kunyuwan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值