zoukankan      html  css  js  c++  java
  • CF1559D2 Mocha and Diana (Hard Version)

    CF1559D2 Mocha and Diana (Hard Version)

    思路

    以下,两图分别称为 A , B

    首先,来证明一个贪心策略:有能连的边就连,或者说连边不会影响最大值

    考虑一种特殊情况,A 只有两个联通块,记为 x 和 y , B 只有两个联通块

    如果从 x 中选出任意一点都无法连接到 y 中任意一点,那么说明 x 中任意一点和 y 中任意一点在 B 中在一个连通块内

    这样推得 B 仅有唯一联通块,矛盾

    所以上述情况一定可以连一条边

    有一个显然的东西,连一条边会让 A 和 B 的联通块个数同时减 1 ,所以不难发现如果有 A 或 B 有一边成树了,那么一定没有可以连的边了

    那么现在假设 A 有 r 个联通块, B 有 c 个联通块

    不妨假设 A 和 B 中点 1 所在的联通块分别为 pa , pb

    那么,将 A 中除去 pa 之外的视为一个整体, B 中同理,就转换为了上面的特殊情况

    于是按上述可以一直连边直到一边成为一棵树,这显然也是能连的边数的最大值

    那么贪心策略得证

    考虑实现

    首先,贪心将所有能和 1 连的点连接

    那么现在图上只有三类点,在 A 和 B 与 1 联通,仅在 A 与 1 联通,仅在 B 与 1 联通

    首先发现,第一类点没任何用,它不能任何点相连

    然后显然的,一个第二类点可以和任意一个第三类点相连,因为他们不在同一个联通块

    于是就可以贪心的连接了

    只是要注意,连接可能会使后两类点变为第一类点,判断一下就好

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef const int& cint;
    
    const int mod = 1e9+7;
    const int inf_int = 0x7fffffff;
    const ll inf_ll = 0x7fffffffffffffff;
    const double ept = 1e-9;
    
    typedef pair<int,int> pii;
    int n, m1, m2;
    int bcj[100001][2];
    
    int fd(cint x, cint st) {
        return bcj[x][st] == x ? x : bcj[x][st] = fd(bcj[x][st], st);
    }
    
    int main() {
        cin >> n >> m1 >> m2;
        int u, v;
        for(int i=1; i<=n; i++) bcj[i][0] = bcj[i][1] = i;
        for(int i=1; i<=m1; i++) {
            cin >> u >> v;
            u = fd(u, 0), v = fd(v, 0);
            if(u < v) swap(u, v);
            bcj[u][0] = v;
        }
        for(int i=1; i<=m2; i++) {
            cin >> u >> v;
            u = fd(u, 1), v = fd(v, 1);
            if(u < v) swap(u, v);
            bcj[u][1] = v;
        }
        vector<pii> e;
        for(int i=2; i<=n; i++) {
            int s1 = fd(i, 0), s2 = fd(i, 1);
            if(s1 != 1 && s2 != 1) {
                bcj[s1][0] = 1;
                bcj[s2][1] = 1;
                e.push_back( {1, i} );
            }
        }
        queue<int> r[2];
        for(int i=2; i<=n; i++) {
            int s1 = fd(i, 0), s2 = fd(i, 1);
            if(s1 == 1 && s2 != 1) r[0].push(i);
            if(s1 != 1 && s2 == 1) r[1].push(i);
        }
        while(!r[0].empty() && !r[1].empty()) {
            while(!r[0].empty() && fd(r[0].front(), 0) == 1 && fd(r[0].front(), 1) == 1) r[0].pop();
            while(!r[1].empty() && fd(r[1].front(), 0) == 1 && fd(r[1].front(), 1) == 1) r[1].pop();
            if(!r[0].empty() && !r[1].empty()) {
                int s1 = r[0].front(), s2 = r[1].front();
                r[0].pop(), r[1].pop();
                bcj[fd(s2, 0)][0] = 1;
                bcj[fd(s1, 1)][1] = 1;
                e.push_back( {s1, s2} );
            }
        }
    
        cout << e.size() << endl;
        for(auto k: e) {
            cout << k.first << ' ' << k.second << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    nyoj999 师傅又被妖怪抓走了 (预处理+bfs+状态压缩)
    使用逆波兰式进行表达式求值
    [moses笔记]编译含有nplm的moses解码器
    菲波那契数列编程实现
    引领网页设计潮流的优秀网页作品赏析
    MFC中获取各个窗口之间的句柄或者指针对象的方法
    UVALive 6529 Eleven 区间dp
    jquery 实现菜单的下拉菜单
    数字图像和视频处理的基础-第4周运动预计matlab练习题
    setjmp与longjmp
  • 原文地址:https://www.cnblogs.com/ullio/p/15154454.html
Copyright © 2011-2022 走看看