翻译
给你一个图,这个图里面会有一些长方形与正方形,只要他们的四角中的任意三个角有一个\(X\)的话(请饶恕我这么形容),那么他就会在空缺的角形成一个新的\(X\),你可以变出来一个\(X\),给你这个图的大小以及哪里有\(X\),问你至少要变出几个\(X\)才可以使得全图都是\(X\)。
思路
不亏是明星团队出的题,代码量不大但是思维坑啊。那么我就不绕了,直接入正题(听说有人五分钟切了这道题?)
这道题熟练图论的人可能会想到办法,按照套路,我们可以把有\(X\)的格子他们的行和列看为两个点,然后把全图跑一边,这样会形成一个图,那么这个图会长啥样?
我们先弄一下\(2*2\)的,假设他三个角都有了\(X\)。那么可能是长下面的一种。
感觉到了什么,没错,这个图是联通的啊!只要有三个边四个点(四个点是格子的四角)一定是联通的!而且加不加第四个已经无所谓了?是不是?我们再以\(2*2\)为例子,看看只有两个边的情况。
你可以容易的想到无论只有两个边或一个边或没有(一个边是一个\(X\)哦!),都不是联通的,这个时候,我们就想帮他联通。建一条边的话要变一次\(X\),一直到整个图联通为止。就像,上图,每个加一个\(X\)就好了,因此答案是\(1\)
我们再上一下样例的图(上面是行,下面是列):
答案是\(1\),你就会想,这不是要加两条边吗??
这就怪了??但是你仔细一想啊,上面两个图的联通块个数都是二,答案都是一!没错是联通块的个数再减一!!!
至此,我很啰嗦的啰嗦完了这道看上去啰嗦但是思想好代码不啰嗦的啰嗦题目,下面是超短代码,我竟然会给注释。
Code
#include<bits/stdc++.h>
using namespace std;
int n,m,q;
bool vis[500010];
vector<int>e[500010];
void dfs(int u)//最简单的求联通分量
{
vis[u]=1;
int sz=e[u].size();
for(int i=0;i<sz;i++)
if(!vis[e[u][i]])
dfs(e[u][i]);
}
int x, y,ans;
int main ()
{
cin>>n>>m>>q;
while(q--)
cin>>x>>y, e[x].push_back(y+n), e[y+n].push_back(x);//为了好搜,于是行正常,列要加上X的个数
for(int i=1;i<=n+m;i++)
if(!vis[i]) ans++, dfs(i);//统计答案
cout<<ans-1<<endl;
return 0;
}
原文地址:https://www.cnblogs.com/lyfoi/p/9485074.html
时间: 2024-09-30 00:45:56