2018年全国多校算法寒假训练营练习比赛(第四场) D.小明的挖矿之旅(图论,图连通)

题目描述

这个挖矿游戏会给出一个n*m个格子的地图,每个格子都有黄金。在游戏开始时小明会随机出现在地图的某一个格子当中。小明可以将他所在的格子的黄金收归囊中,并且还可以向下或者向右移动,然后继续收集黄金。地图上某些格子是障碍物,小明不能移动到有障碍物的格子上。不过,在游戏开始时,小明可以随意地在地图上放置传送门。传送门可以传送到地图上某一个确定的格子,传送门放置的位置和该传送门传送的位置在游戏开始之前必须放置和设置好传送地点。小明有无数个传送门可以使用,但是每次使用传送门所需要的游戏币也是很多的。小明想要至少要使用多少个传送门才能让他在游戏时无论出现在哪个格子,他都能拿到地图上的所有金子。

输入描述:

有多组测试数据。 对于每一组数据: 第一行输入两个整数n和m(0

输出描述:

输出一行。此行包括一个整数,表示小明所需传送门数量的最小值。

输入

3 3
...
.#.
...

输出

1

思路

首先题意很明确,有一个1000*1000迷宫,里面有墙和空地,每块空地上都有金子。开始时你会被放在地图的任意空地,之后你只可以往右走或者往下走,边走可以边把路过的金子收入囊中。游戏开始时允许你在地图的一些格子放一些传送门,对于每一个传送门,你也要规定一个传送的位置,当你在游戏开始之后到达某个传送门,可以传送到该传送门的指定位置。问你一开始最少放置多少个传送门可以保证无论开局时你的位置在哪里,都可以把所有金子拿走。

我们只需要把传送门安放在无路可走的位置(出度为0),传送的位置只需要选择没有前驱(入度为0)的位置,所以我们要的答案就是找出出度为0和入度为0的点数量的最大值,特判空地小于等于1的情况(和给了一个有向图,问需要加多少条边使这个图强连通类似)

代码

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const int N=1000+2;
char s[N][N];
int in[N][N],out[N][N];
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)
        scanf("%s",s[i]);
    int cnt=0;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            if(s[i][j]=='.')
            {
                cnt++;
                if(i+1<n&&s[i+1][j]=='.')
                    out[i][j]=in[i+1][j]=1;
                if(j+1<m&&s[i][j+1]=='.')
                    out[i][j]=in[i][j+1]=1;
            }
    if(cnt<=1)
    {
        puts("0");
        return 0;
    }
    int a=0,b=0;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            if(s[i][j]=='.')
            {
                if(!in[i][j])
                    a++;
                if(!out[i][j])
                    b++;
            }
    printf("%d\n",max(a,b));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值