Codeforces 1012B Chemical table (思维+二分图)

<题目链接>

题目大意:
给定一个n*m的矩阵网格,向其中加点,对于一个组成矩形的四个点中如果有三个点中有元素,那么第四个点中会自动产生新的元素。问你最少再加多少个点能够填满这个网格。
解题分析:
不是很好想,先将行列看成两个集合,每次加点操作,就相当于x集合向y集合连了一条边。
本题可以巧妙的转化为,要使x和y集合所有的点都连通最少需要添加几条边。初始情况需要n+m-1条边(因为两个集合有n+m个点,且相同集合不能连边)。
然后根据题目已经给出的边判断最终的连通块个数,用并查集来判连通。主要是这个转化的思想不好想。

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

template<typename T>
inline void read(T&x){
    x=0;int f=1;char c=getchar();
    while(c<'0'||c>'9'){ if(c=='-')f=-1;c=getchar(); }
    while(c>='0'&&c<='9'){ x=x*10+c-'0';c=getchar(); }
    x*=f;
}
#define REP(i,s,t) for(int i=s;i<=t;i++)
const int N = 2e5+5;
int fa[N<<1];

int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }

inline bool merge(int x,int y){
    int f1=find(x),f2=find(y);
    if(f1!=f2){ fa[f1]=f2;return true;}
    return false;
}

int main(){
    int n,m,q;
    read(n);read(m);read(q);
    REP(i,0,n+m)fa[i]=i;
    int ans=n+m-1;       //其实就是最少用多少条边,使得这n+m个点连通,最多只需要用n+m-1条
    REP(i,1,q){
        int a,b;read(a);read(b);
        b+=n;
        if(merge(a,b))ans--;      //如果这条边有效,则需要的边数--
    }
    cout<<ans<<endl;
}

 

posted @ 2019-06-08 15:25  悠悠呦~  阅读(235)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end