Codeforces 1344B/1345D


半天看不懂题意只能补。。。


题面

Prob




题意

给定一张黑白图,要求放置南北磁极,南磁极不可移动(每行每列至少要有一个南磁极)

每次可以激活一对在同行或同列的南北磁极,使得北磁极向南磁极移动一格

要求在所有可能的移动过程中,北磁极不能到达白块,且又可以到达所有黑块

问最少需要放置多少个北磁极,才能走遍图中所有黑块

如果无法放置,输出 -1




解题思路


①如果某行或者某列存在两段及以上黑色块组成的线段

例如:

PIC0

因为每行或每列必定存在至少一个南磁极,所以肯定存在一个移动方式使得北磁极经过中间的那段白色块

所以这种情况出现时不符题意,输出 -1

由此可得,只有黑色块组成线段只存在一段时才符合题意

所以例如: ..###.. | ###.... | ....### 都可行

而样例 2 的第一列: #..# 不可行


②如果某列全空且没有行全空,或者某行全空且没有列全空

例如:

PIC1

上图中第三列全空,但没有任何一行为空

又因为每列必须有至少一个南磁极

所以也一定存在一种移动方式能够让北磁极移动到这个全白的列上,不符题意


③如果存在某列全空,且存在某行全空

例如:

PIC2

那么只要让南磁极放置在交叉点上,则不会影响分割出来的四个象限里的北磁极的移动

即:

PIC3

如果存在多个交叉点,则在每个交叉点上都放置一个南磁极即可

例如:

PIC4


综上我们可以得到:

  1. 每一行或者每一列至多存在一条由黑色块组成的线段
  2. 全白行与全白列,要么同时存在,要么同时不存在

于是我们就把北磁极的移动路线固定在了每个黑色连通块之中

最后通过bfs或者dfs求出连通块数量即可




代码实现

在判断黑色块线段数量时,引入变量kd,初始值为0

循环某行或者某列

如果碰到了 '#' 且 kd 是 0 则变成 1 ,是 2 则直接输出 -1 并结束程序

如果碰到了 '.' 且 kd 是 1 则变成 2

所以最后如果kd==0,说明整行全是白色块

如果kd==1,说明这一行只有一段黑色块,且最后一个位置为黑色块

如果kd==2,说明这一行只有一段黑色块,且最后一个位置为白色块

否则就是直接输出 -1 的情况,说明由两段黑色块线段




完整程序

(46ms/2000ms)

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;

char mp[1050][1050];
int n,m,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};

inline bool prim(int x,int y)
{
    return x>0&&y>0&&x<=n&&y<=m;
}

void bfs(int x,int y)
{
    mp[x][y]='.';
    queue<P> q;
    q.push(P(x,y));
    while(!q.empty())
    {
        P pd=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int px=pd.first+dx[i],py=pd.second+dy[i];
            if(prim(px,py)&&mp[px][py]=='#')
            {
                mp[px][py]='.'; //把访问到的黑色块直接变成其他值即可
                q.push(P(px,py));
            }
        }
    }
}

void solve()
{
    cin>>n>>m;
    
    bool emptyRow=false,emptyColumn=false;
    
    for(int i=1;i<=n;i++)
    {
        cin>>(mp[i]+1);
        int kd=0;
        for(int j=1;j<=m;j++) //遍历行
        {
            if(mp[i][j]=='.')
            {
                if(kd==1)
                    kd=2;
            }
            else
            {
                if(kd==0)
                    kd=1;
                else if(kd==2)
                {
                    cout<<"-1
";
                    return;
                }
            }
        }
        if(kd==0)
            emptyColumn=true; //说明这行全是白色块
    }
    
    for(int j=1;j<=m;j++)
    {
        int kd=0;
        for(int i=1;i<=n;i++)//遍历列
        {
            if(mp[i][j]=='.')
            {
                if(kd==1)
                    kd=2;
            }
            else
            {
                if(kd==0)
                    kd=1;
                else if(kd==2)
                {
                    cout<<"-1
";
                    return;
                }
            }
        }
        if(kd==0)
            emptyRow=true; //说明这列全是白色块
    }
    
    if(emptyColumn!=emptyRow) //如果行全白且没有列全白,或者列全白且没有行全白
    {
        cout<<"-1
";
        return;
    }
    
    int ans=0;
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) //遍历整张图
            if(mp[i][j]=='#') //如果存在没有访问到的黑色块
            {
                bfs(i,j);
                ans++;
            }
    
    cout<<ans<<'
';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

原文地址:https://www.cnblogs.com/stelayuri/p/12843792.html