D. Monopole Magnets

time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
A monopole magnet is a magnet that only has one pole, either north or south. They don’t actually exist since real magnets have two poles, but this is a programming contest problem, so we don’t care.

There is an n×m grid. Initially, you may place some north magnets and some south magnets into the cells. You are allowed to place as many magnets as you like, even multiple in the same cell.

An operation is performed as follows. Choose a north magnet and a south magnet to activate. If they are in the same row or the same column and they occupy different cells, then the north magnet moves one unit closer to the south magnet. Otherwise, if they occupy the same cell or do not share a row or column, then nothing changes. Note that the south magnets are immovable.

Each cell of the grid is colored black or white. Let’s consider ways to place magnets in the cells so that the following conditions are met.

There is at least one south magnet in every row and every column.
If a cell is colored black, then it is possible for a north magnet to occupy this cell after some sequence of operations from the initial placement.
If a cell is colored white, then it is impossible for a north magnet to occupy this cell after some sequence of operations from the initial placement.
Determine if it is possible to place magnets such that these conditions are met. If it is possible, find the minimum number of north magnets required (there are no requirements on the number of south magnets).

Input
The first line contains two integers n and m (1≤n,m≤1000) — the number of rows and the number of columns, respectively.

The next n lines describe the coloring. The i-th of these lines contains a string of length m, where the j-th character denotes the color of the cell in row i and column j. The characters “#” and “.” represent black and white, respectively. It is guaranteed, that the string will not contain any other characters.

Output
Output a single integer, the minimum possible number of north magnets required.

If there is no placement of magnets that satisfies all conditions, print a single integer −1.

Examples
inputCopy
3 3
.#.

##.
outputCopy
1
inputCopy
4 2

.#
.#

outputCopy
-1
inputCopy
4 5
…#
####.
.###.
.#…
outputCopy
2
inputCopy
2 1
.

outputCopy
-1
inputCopy
3 5



output
这个题在codeforces比赛中看不懂题意,硬是猜了个大概意思,但是忽略了条件三,最后思路总结。
题意:设定S极磁铁(每行每列至少有一个)任意激活,使N极磁铁能够遍历黑格,而且不会进入白格,求N极磁铁的最小数量。

1.S极磁铁使N极磁铁能够遍历黑块区。

当整个图案联通时(一个连通块)

我们只需在图案的边缘部位设定S极磁铁,然后随便一个N极磁铁即可
SSS
SNS
SSS
当图案有独立部分(多个连通块)

#…
.##
.##
我们便将他们视为上一种情况的叠加(也就是连通块的数量)
N…
.S&N S
.S S

2.S极磁铁要使N极磁铁不会进入白块

要知道每一行或每一列两个S极磁铁之间(包括两端)的所有的方格N极磁铁都可以进入,也就是要使两个S极磁铁间不存在白块。也就是每一行或每一列所有独立黑块的边缘间不存在白块。
例如

#…

.## …

#…

边缘之间都有白块,不满足条件。

3. 因为每一行每一列至少有一个S极块

只考虑黑块区域的边缘还有可能有的行或列没有S极块,这时讨论一个黑块都没有的行与列,当加入S块时,这时若如果它对应的列与行中有黑块黑块一定可能进入白块区。

但是一旦存在没有黑块的行与列两者时,它们一定有交点而且交点不会影响黑块的移动。
##.
##.

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
using namespace std;
int T_T[200000];
int m,n;
char flag[2000][2000];
int vis[2000][2000],cnt,wsad[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
void dfs(int x,int y)
{//kkkkkkkkkkkk
    if(flag[x][y]=='.'||x<1||x>m||y<1||y>n||vis[x][y])
        return ;
    vis[x][y]=1;
    for(int i=0; i<4; i++)
        dfs(x+wsad[i][0],y+wsad[i][1]);
}
int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        memset(vis,0,sizeof(vis));
        int n_j=0,h_j=0;
        cnt=0;int num=0;
        for(int i=1; i<=m; i++)
            scanf("%s",flag[i]+1);
        bool judge=false;
        for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++){
            if(flag[i][j]=='.')num++;
            else break;
        }
        if(num==n*m){cout<<0<<endl;continue;}//判断是否有黑块(其实没有必要独立写出来)
        for(int i=1; i<=m; i++)
        {
            int go=0;
            for(int j=1; j<=n; j++)
            {
                if(flag[i][j]=='#')
                {
                    if(go==0)go=1;
                    if(go==2){judge=true;//判断区域边缘间是否有白块
                    break;}
                }
                else if(go)
                {
                    go=2;
                }
            }
            if(judge)
                break;
            if(!go)
            {
                n_j++;//判断是否存在整个列都没有黑块的情况
            }
        }
        if(judge)
        {
            cout<<-1<<endl;
            continue;
        }
        for(int i=1; i<=n; i++)
        {
            int go=0;
            for(int j=1; j<=m; j++)
            {
                if(flag[j][i]=='#')
                {
                    if(!go)go=1;
                    if(go==2){judge=true;
                    break;}
                }
                else if(go)
                {
                    go=2;
                }
            }
            if(judge)
                break;
            if(!go)
            {
                h_j++;判断是否存在整个行都没有黑块的情况
            }
        }
        if(judge)
        {
            cout<<-1<<endl;
            continue;
        }
        if(!(n_j==0&&h_j==0)){
            if(n_j==0||h_j==0){
                cout<<-1<<endl;
                continue;
            }
        }
        for(int i=1; i<=m; i++)
            for(int j=1; j<=n; j++)
                if(flag[i][j]=='#'&&vis[i][j]==0)
                {
                    dfs(i,j);//连通块个数判断
                    cnt++;
                }
        cout<<cnt<<endl;
    }

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值