Codeforces Round#639 1345D.Monopole Magnets(构造)

最近一个月基本处在只偶尔打下contest不刷题的状态,结果就是把把拉胯,于是rating
在这里插入图片描述
这还是幸亏本场unrated了。让人不禁感叹这就是努力型选手吗,真是有够好笑的呢

痛定思痛,为了督促自己不要疏于练习,定个小目标,以后把每次contest最后做不出来(或者很勉强做出来)的题自己再好好理解总结一下(看难度和题数尽量做到Div.2的D或E题,1900-2200的),参考内容包括但不仅限于出题人给出的tutorial和别人的ac代码以及其他非官方的题解。

题目描述:

D. Monopole Magnets

time limit per test 2 seconds

memory limit per test 256 megabytes

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

input

3 3
.#.
###
##.

output

1

input

4 2
##
.#
.#
##

output

-1

input

4 5
....#
####.
.###.
.#...

output

2

input

2 1
.
#

output

-1

input

3 5
.....
.....
.....

output

0

算法标签:构造

简单翻译一下:在一张n*m的棋盘上,任意放置北磁铁和南磁铁(位置、数量不限),但每一行、每一列都至少要有一个南磁铁,其中南磁铁位置固定,北磁铁能够被任意一个在同一行/同一列的南磁铁吸引,向其对应方向移动一格。现给出一个用黑白涂色后的棋盘,#代表黑,.代表白,黑表示北磁铁经过一系列移动后能够到达该格,白表示北磁铁不论怎样都不能到达该格。求符合要求的摆法中,北磁铁最少的数量(不对南磁铁的数量做要求)。若不存在则输出-1。

读完题发现作为构造题,自由量还是挺多的,不知道从哪里下手的话,可以先从解不存在的情况开始分析。

先给结论,当以下任意一条满足时,解不存在。

1. 某一行或某一列上,任意两块黑色格子之间有白色格子

2. 某一行全白,但不存在全白的列。或某一列全白,但不存在全白的行。

依次证明一下,观察样例2,给出的示例如图

在这里插入图片描述

发现黑色部分的的形状和其他样例的区别在于黑色格子的边界处有一块是凹进去的。也就是说,第一列中A、B两个黑色格子之间存在白色格子C、D
在这里插入图片描述
由于第一列至少有一个南磁铁,分类讨论一下南磁铁的位置:

1、 南磁铁在A,则北磁铁到达B处后,会被吸引向上移动至C,矛盾

2、 南磁铁在B,则北磁铁到达A处后,会被吸引向下移动至D,矛盾

3、 南磁铁在C或D,则A和B的北磁铁都会被吸引,矛盾

因此无论南磁铁怎么放,至少会使A、B中的一个被吸引至白色格子,产生矛盾,因此,任意两个黑色格子之间不能有白色格子。

接下来证明第二条。

假设有一列是全白的(行同理),那么如何选择南磁铁的位置才能保证不产生矛盾呢?
在这里插入图片描述
考虑以上这种情况,要确定第一列南磁铁的位置,唯一可行的位置是第一列的第二行。因为要确保该南磁铁不会对任何北磁铁产生吸引,否则北磁铁一定能被吸引至该格子,但该格子是白的,矛盾。所以必须选择把南磁铁放在全白的一行里,也就是说,南磁铁所在的行和列都是全白的,没有北磁铁会受其影响。

于是两种一定无解的情况找到,直觉上很难再想到其他会导致无解的情况,就可以开始构造一种最优(即北磁铁数量最少)的摆法。(只需要证明这种构造方法在排除了前两种无解的情况后总是成立,即可证明其正确性,所以这里的“直觉”还是严谨的)

因为目标是使得北磁铁数量最少,且北磁铁总是上下左右移动,那么很容易想到一种理想的摆法:

第一步:在每一个黑格子上都放一个南磁铁,那么对于每一块联通(指上下左右相连)的黑格子块,只需要放一个北磁铁即可到达该联通块的每一个位置。

实际上这种摆法是可以被证明是正确的。在基于“任何一行都只有一段连续黑色格子”的前提下,该行所有的南磁铁使北磁铁在行上的移动都被限制在了黑色格子的范围内。也就是说,确保了该行的白色格子不会有北磁铁能够通过行上的移动到达。列同理。进而得出任何白色格子既无法通过行上的移动到达,也无法通过列上的移动到达,也就是不可能到达,符合题意。
在这里插入图片描述

第二步:确保每一行每一列都有一个南磁铁。假如该行不是全白的,那么经过第一步它已经至少存在一个南磁铁了,不需要再额外添加。假如该行(第i行)是全白的,在基于“存在某一列j也是全白的”的前提下,可以将南磁铁放在(i,j)这个格子,能够确保它不会对任何北磁铁产生影响。列同理

构造完毕。通过构造方法的正确性,可以反过来证明,无解的情况有且仅有以上提到的两种。

代码实现时只需要判断两个无解的情况,若无解直接输出-1,若有解,则用记忆化DFS计算出联通黑块的块数,就是最终所需要的北磁铁的个数了。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;

const int N=1e3+5;

char s[N][N];

bool vis[N][N];

const int dire[4][2]={{1,0},{-1,0},{0,1},{0,-1}};

int T,n,m;

bool column,row;

void dfs(int x,int y)
{
    vis[x][y]=1;
    for (int i=0;i<4;i++)
    {
        int cx=x+dire[i][0];
        int cy=y+dire[i][1];
        if (cx>=0 && cx<n && cy>=0 && cy<m && !vis[cx][cy] && s[cx][cy]=='#')
            dfs(cx,cy);
    }
}

int main()
{
    int ans=0;
    cin>>n>>m;
    for (int i=0;i<n;i++) scanf("%s",s[i]);
    for (int i=0;i<n;i++)
    {
        int cnt=0;
        for (int j=0;j<m;j++)
            if (s[i][j]=='#' && (s[i][j-1]!='#'||j==0))
                cnt++;
        if (cnt>=2)
        {
            printf("-1");
            return 0;
        }
        if (!cnt) row=1;
    }
    for (int j=0;j<m;j++)
    {
        int cnt=0;
        for (int i=0;i<n;i++)
            if (s[i][j]=='#' && (s[i-1][j]!='#'||i==0))
                cnt++;
        if (cnt>=2)
        {
            printf("-1");
            return 0;
        }
        if (!cnt) column=1;
    }
    if (row^column)
    {
        printf("-1");
        return 0;
    }
    for (int i=0;i<n;i++)
        for (int j=0;j<m;j++)
        {
            if (s[i][j]=='#' && !vis[i][j])
            {
                ans++;
                dfs(i,j);
            }
        }
    printf("%d",ans);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值