• BZOJ3624: [Apio2008]免费道路


    考虑到这 k 条0边中肯定是有一些边是必须要加的
    而其他的0边是可以被其他边替代的,并不影响连通性

    那首先要确定哪些0边是必要的0边

    先拿所有1边做生成树,然后考虑加入0边
    加入后会使联通块个数减少的0边就是必须要加的
    不过还有以下特殊情况:

    显然这两条边中只能找一条做为必要的边
    那就找到了之后把它加进选入边集中就行

    这时就会有一种不合法的情况,就是必需的边数 > k

    之后把必需边加入的边先加进去
    之后不断加入0边直到总共加入 k 条

    这里又会出现不合法的情况,就是加不够 k 条

    之后把所有1边加入就可以了

    这里还会有一种不合法的情况,就是你建不出来一棵生成树

    这样就可以过了

    这题其实思路挺自然的,静下心来想肯定是会的


     代码:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cctype>
    #include <cstdio>
    #include <locale>
    using namespace std;
     
    const int MAXN = 20005, MAXM = 100005;
     
    struct EDGE {
        int x, y, typ;
        bool imp, intree;
    }edge[MAXM];
    int n, m, k, tot, blk;
    int fa[MAXN];
     
    inline int rd() {
        register int x = 0, c = getchar();
        while (!isdigit(c)) c = getchar();
        while (isdigit(c)) {
            x = x * 10 + (c ^ 48);
            c = getchar();
        }
        return x;
    }
    inline void resetfa() {
        for (int i = 1; i <= n; ++i) fa[i] = i;
    }
    int findfa(int x) {
        return ((fa[x] == x) ? (x) : (fa[x] = findfa(fa[x])));
    }
    inline bool link(int x, int y) {
        int fx = findfa(x), fy = findfa(y);
        if (fx == fy) return false;
        fa[fx] = fy;
        return true;
    }
    inline bool stick(int x, int y) {
        return (findfa(x) == findfa(y));
    }
     
    int main() {
        n = rd(); m = rd(); k = rd();
        resetfa();
        for (int i = 1; i <= m; ++i) {
            edge[i].x = rd(); edge[i].y = rd();
            edge[i].typ = rd();
        }
        for (int i = 1; i <= m; ++i) if (edge[i].typ) {
            link(edge[i].x, edge[i].y);
        }
        for (int i = 1; i <= m; ++i) if (!edge[i].typ && !stick(edge[i].x, edge[i].y)) {
            link(edge[i].x, edge[i].y);
            edge[i].imp = true;
            ++tot;
        }
        if (tot > k) {
            puts("no solution");
            return 0;
        }
        resetfa();
        blk = n;
        tot = 0;
        for (int i = 1; i <= m; ++i) if (edge[i].imp) {
            link(edge[i].x, edge[i].y);
            ++tot;
            --blk;
            edge[i].intree = true;
        }
        for (int i = 1; i <= m && tot < k; ++i) if (!edge[i].typ && !edge[i].imp) {
            if (link(edge[i].x, edge[i].y)) {
                ++tot;
                --blk;
                edge[i].intree = true;
            }
        }
        if (tot < k) {
            puts("no solution");
            return 0;
        }
        for (int i = 1; i <= m && blk != 1; ++i) if (edge[i].typ) {
            if (link(edge[i]. x, edge[i].y)) {
                --blk;
                edge[i].intree = true;
            }
        }
        if (blk != 1) {
            puts("no solution");
            return 0;
        }
        for (int i = 1; i <= m; ++i) if (edge[i].intree) {
            printf("%d %d %d
    ", edge[i].x, edge[i].y, edge[i].typ);
        }
        return 0;
    }
    
  • 相关阅读:
    编程的核心思维
    对编程语言的一点总结
    End Poem
    linux下的errno对照表
    C++中的三个特殊宏:__FILE__,__FUNCTION__和__LINE__
    算法——从斐波那契数列谈起(一)
    [题解][HNOI2002][Luogu P2234] 营业额统计
    用STL水平衡树的题
    浅谈C++的智能指针
    cnblog代码高亮优化(tomorrow主题)
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9858866.html
Copyright © 2020-2023  润新知