[Codeforces 1012B] Chemical table

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/81304498

题目链接:http://codeforces.com/problemset/problem/1012/B

题目大意:
有一个n*m的矩阵, 初始时有q个点, 对于任意一个面积不为0的矩形来说, 如果具备其中三个顶点, 则可以产生剩下的第四点, 求最少补充多少个点能够生成所有这n*m个点。 ( n , m 2 10 5 , q m i n ( n m , 2 10 5 ) )

题目思路:
考虑一个二分图, 左边n个点, 右边m个点, 对于原来的点(x,y), 可以看作x->y的边。 考虑一条路径x->y, 如果x,y直接相连, 说明原来就有点, 无须添加, 否则, 根据二分图的性质, 一定是条长度>=3的为奇数的交错路径, 而考虑前三个点x->a->b, 根据定义, 可以生成x->b这条边, 故交错路径长度-2, 一直做下去, 会直接产生x->y这条边。 故对于一个联通块而言, 其中的所有点都可以产生出来。
所以答案就是联通分量数-1。

Code:

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

#define ll long long
#define id(x, y) ((x - 1) * m + y)

using namespace std;

const int N = (int)4e5 + 10;

int n, m, q, fa[N];

int find(int x){
    if (x != fa[x]) return fa[x] = find(fa[x]);
    return x;
}

void unit(int r1, int r2){
    r1 = find(r1), r2 = find(r2);
    if (r1 != r2) fa[r2] = r1;
}

int main(){

    scanf("%d %d %d", &n, &m, &q);
    for (int i = 1; i <= n + m; i ++)
        fa[i] = i;

    while (q --){
        int i, j;
        scanf("%d %d", &i, &j);
        unit(i, n + j);
    }

    int ans = 0;
    for (int i = 1; i <= n + m; i ++)
        if (find(i) == i) ans ++;

    printf("%d", ans - 1);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013578420/article/details/81304498