D1. Mocha and Diana (Easy Version)(并查集判环)

题目:

D1. Mocha and Diana (Easy Version)(并查集判环)_第1张图片

D1. Mocha and Diana (Easy Version)(并查集判环)_第2张图片 

大致题意:

有小A和小B,他们两个各有一个森林(无向无环图)(可能有孤立点),两个森林中n个节点都相互对应, 已知两个森林的边的连接情况,进行添加边的操作(两森林添加一样的边,并保证添加边后两森林还是森林),求能连接边的条数的最大值。

思路分析:

森林是无向无环图,森林中有 n 个节点,那么森林中至多有 n  - 1 条边。

那么要想得到连边数的最大值,要连的线段条数为min(n - m1 -  1, n - m2 - 1) ,其中 m1 为小A森林中 边的个数, m2 为小B森林中 边的个数。

我们确定了能连的边的条数,下面确定可以连的边的要求

1.只能连两个图都没连过的边。

2.连一条边要保证这条边在两个图里都不会连接成环。

在实现上

我们用b[][]存储两个图都连过的边,运用并查集的思想判断是否会在图中连接出环(如果要连的这条边的两个端点是同一个集合中的,那么这条边连接会使图中出现环)

贴代码:

#include 

using namespace std;

const int N = 1010;

int n, m1, m2;
int fa1[N], fa2[N];
bool b[N][N];//存两森林的合并图中两点间是否存在边

void init(){
    for(int i = 1; i <= n; i ++ ){
        fa1[i] = i;
        fa2[i] = i;
    }
}

int find1(int x){
    if(fa1[x] != x) fa1[x] = find1(fa1[x]);
    return fa1[x];
}
int find2(int x){
    if(fa2[x] != x) fa2[x] = find2(fa2[x]);
    return fa2[x];
}

void merge1(int x, int y){
    fa1[find1(x)] = find1(y);
}
void merge2(int x, int y){
    fa2[find2(x)] = find2(y);
}

int main(){

    cin >> n >> m1 >> m2;

    init();//并查集模板初始化

    for(int i = 1; i <= m1; i ++ ){
        int x, y;
        cin >> x >> y;
        b[x][y] = true;
        merge1(x, y);//维护端点所在集合,后期判环使用
    }
    for(int i = 1; i <= m2; i ++ ){
        int x, y;
        cin >> x >> y;
        b[x][y] = true;
        merge2(x, y);
    }

    int cnt = min(n - m1 - 1, n - m2 - 1);
    cout << cnt << endl;
    for(int i = 1; i <= n; i ++ ){
        for(int j = 1; j <= n; j ++ ){
            //判断条件:还有可连的边没连,这条边在两图中都没出现过,连接这条边在两图中都不会成环
            if(i != j && !b[i][j] && cnt && find1(i) != find1(j) && find2(i) != find2(j){
                merge1(i, j);
                merge2(i, j);
                b[i][j] = true;
                cnt -- ;
                cout << i << " " << j << endl; 
            }
            if(!cnt) break;
        }
    }

    system("pause");
    return 0;
}


 

你可能感兴趣的:(写着玩,c++,算法)