luoguP7479 至曾是英雄的您 题解

题意简述

题目大意是给出一些黑棋,需要我们往里面依次放白棋,问是否可以满足无论怎么依次放白棋的过程中黑棋都能存活。

题目分析

看到样例解释,我们可以想到把“白棋恰好将黑棋全部吃掉”的局面画出来。

对于下面这个输入数据:

.*.*.
.***.
.....

我们将白棋用 @ 表示:

@*@*@
@***@
.@@@.

观察上面的图像,可以发现此时棋盘中最上面一行的第三个棋子被黑棋包围,称它目前处于“不合法”状态。所以,在依次放置白棋的过程中,这个“不合法”的连通块一定是最后放置,从而将黑棋提掉。

稍微思考一下可以得出:对于每一个白棋的连通块,此时它“不合法”(四周都有黑棋或者边界)的连通块数量必须 \(\leq\) 1。否则,想要到达恰好吃掉黑棋的情况,白棋放置的过程中不能满足同时有两个连通块“不合法”。

也就是说,我们只需要先把恰好能吃掉全部黑棋时的白棋填上,再判断白棋“不合法”的连通块数量是不是大于 1 即可。

代码

此代码的棋盘中 .0 表示, *1 表示, @2 表示。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline ll read(){}

ll T,n,m;
int a[2004][2004]; //棋盘
int ok=0; //统计白棋“不合法”连通块的数量
int dx[4]= {0,0,1,-1},dy[4]= {1,-1,0,0}; 
bool ff=0; //搜索时的标记

inline void C() //清空
{
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)
            a[i][j]=0;
    ok=0;
}

inline void dfs(int x,int y)
{
    if(a[x][y]==1) return;
    if(a[x][y]==0) //如果白棋“存活”,标记设为1
    {
        ff=1;
        return;
    }
    a[x][y]=1;
    for(int i=0; i<4; ++i) 
    {
        int ny=dy[i]+y;
        int nx=dx[i]+x;
        if(ny<=0 || nx<=0 || ny>m || nx>n) continue;
        dfs(nx,ny);
    }
}

int main()
{
    T=read();
    while(T--)
    {
        n=read();
        m=read();
        C(); //初始化
        
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j) //处理棋盘
            {
                char ch;
                cin>>ch;
                if(ch=='.') 
                    a[i][j]=0;
                if(ch=='*')
                    a[i][j]=1;
            }

        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j) //把恰好能吃掉全部黑棋时的白棋填上
            {
                if(a[i][j]==1)
                {
                    if(a[i-1][j]!=1) a[i-1][j]=2;
                    if(a[i+1][j]!=1) a[i+1][j]=2;
                    if(a[i][j-1]!=1) a[i][j-1]=2;
                    if(a[i][j+1]!=1) a[i][j+1]=2;
                }
            }

        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=m;++j)
            {
                ff=0; //先标记为“不合法”
                if(a[i][j]==2)
                {
                    dfs(i,j);
                    if(ff==0) 
                        ok++; //累加不合法的次数
                }   
                if(ok>=2) //不合法次数 >=2 了,代表黑棋能活
                {
                    puts("YES");
                    break;    
                }
            }
            if(ok>=2) break; //符合条件时及时跳出
        }
        if(ok<2) puts("NO"); //黑棋不能活
    }
    return 0;
}

EdisonBa

2021.4.6

原文地址:https://www.cnblogs.com/EdisonBa/p/14622709.html