• 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

  • 相关阅读:
    Gym
    [APIO2014] 回文串
    python选课系统
    python面向对象之类成员修饰符
    python面向对象之类成员
    python的shelve模块
    python的re模块
    python的configparser模块
    python的sys和os模块
    python的hashlib模块
  • 原文地址:https://www.cnblogs.com/EdisonBa/p/14622709.html
Copyright © 2020-2023  润新知