zoukankan      html  css  js  c++  java
  • BZOJ 3624: [Apio2008]免费道路 [生成树 并查集]

    题意:

    一张图0,1两种边,构造一个恰有k条0边的生成树


    优先选择1边构造生成树,看看0边是否小于k

    然后保留这些0边,补齐k条,再加1边一定能构成生成树

    类似kruskal的证明

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=2e4+5, M=1e5+5;
    typedef long long ll;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int n, m, k, u, v, c, m0, m1, p;
    struct meow{int u, v, c;}a[M], b[M], ans[N];
    int fa[N];
    int find(int x) {return x==fa[x] ? x : fa[x]=find(fa[x]);}
    int flag[N];
    int main() {
        freopen("in","r",stdin);
        n=read(); m=read(); k=read();
        for(int i=1; i<=m; i++) {
            u=read(), v=read(), c=read();
            if(c==1) a[++m1]=(meow){u,v,c};
            else b[++m0]=(meow){u,v,c};
        }
    
        int cnt=0;
        for(int i=1; i<=n; i++) fa[i]=i;
        for(int i=1; i<=m1; i++) {
            u=a[i].u, v=a[i].v;
            int x=find(u), y=find(v);
            if(x==y) continue;
            fa[x]=y;
            if(++cnt == n-1) break;
        }
        for(int i=1; i<=m0; i++) {
            u=b[i].u, v=b[i].v;
            int x=find(u), y=find(v);
            if(x==y) continue;
            fa[x]=y; ans[++p]=b[i]; flag[i]=1;
            if(++cnt == n-1) break;
        }
        if(p > k || cnt < n-1) {puts("no solution"); return 0;}
    
        for(int i=1; i<=n; i++) fa[i]=i;
        for(int i=1; i<=p; i++) fa[find(ans[i].u)] = find(ans[i].v);
        cnt=p;
        if(cnt<k) for(int i=1; i<=m0; i++) if(!flag[i]){
            u=b[i].u, v=b[i].v;
            int x=find(u), y=find(v);
            if(x==y) continue;
            fa[x]=y; ans[++cnt]=b[i];
            if(cnt == k) break;
        }
        for(int i=1; i<=m1; i++) {
            u=a[i].u, v=a[i].v;
            int x=find(u), y=find(v);
            if(x==y) continue;
            fa[x]=y; ans[++cnt]=a[i];
            if(cnt == n-1) break;
        }
        for(int i=1; i<=cnt; i++) printf("%d %d %d
    ",ans[i].u, ans[i].v, ans[i].c);
    }

    2017-10-03 今天又写了一下 以前好像有点问题洛谷wa1

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int N = 1e5+5, M = 1e5+5;
    typedef long long ll;
    inline int read() {
        char c=getchar(); int x=0,f=1;
        while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int n, m, k;
    struct edge {int u, v, c;} e[M];
    int flag[N], fa[N], ans[N];
    int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
    int main() {
        //freopen("in", "r", stdin);
        scanf("%d %d %d", &n, &m, &k);
        for(int i=1; i<=m; i++) e[i].u = read(), e[i].v = read(), e[i].c = read();
        
        for(int i=1; i<=n; i++) fa[i] = i;
        int num = 0;
        for(int i=1; i<=m; i++) if(e[i].c == 0) {
            int f1 = find(e[i].u), f2 = find(e[i].v);
            if(f1 == f2) continue;
            fa[f1] = f2;
            if(++num == n-1) break;
        }
        int one = 0;
        for(int i=1; i<=m; i++) if(e[i].c == 1) {
            int f1 = find(e[i].u), f2 = find(e[i].v);
            if(f1 == f2) continue;
            fa[f1] = f2;
            one++; ans[++ans[0]] = i; flag[i] = 1;
            if(++num == n-1) break;
        }
        if(one > n-k) {puts("no solution"); return 0;}
        if(num < n-1) {puts("no solution"); return 0;}
         
        for(int i=1; i<=n; i++) fa[i] = i;
        num = 0;
        for(int i=1; i<=m; i++) if(e[i].c == 1) {
            int f1 = find(e[i].u), f2 = find(e[i].v);
            if(f1 == f2) continue;
            fa[f1] = f2;
            if(++num == n-1) break;
        }
        int zero = 0;
        for(int i=1; i<=m; i++) if(e[i].c == 0) {
            int f1 = find(e[i].u), f2 = find(e[i].v);
            if(f1 == f2) continue;
            fa[f1] = f2; 
            zero++; ans[++ans[0]] = i; flag[i] = 1;
            if(++num == n-1) break;
        }
        if(zero > k) {puts("no solution"); return 0;}
        
        for(int i=1; i<=n; i++) fa[i] = i;
        num = ans[0];
        for(int i=1, t; i<=ans[0]; i++) t = ans[i], fa[find(e[t].u)] = find(e[t].v);
        if(zero < k) for(int i=1; i<=m; i++) if(!flag[i] && e[i].c == 0) {
            int f1 = find(e[i].u), f2 = find(e[i].v);
            if(f1 == f2) continue;
            fa[f1] = f2;
            ans[++ans[0]] = i; 
            ++num;
            if(++zero == k) break;
        }
        if(num < n-1) for(int i=1; i<=m; i++) if(!flag[i] && e[i].c == 1) {
            int f1 = find(e[i].u), f2 = find(e[i].v);
            if(f1 == f2) continue;
            fa[f1] = f2;
            ans[++ans[0]] = i;
            if(++num == n-1) break;
        }
        
        if(zero != k || num != n-1) {puts("no solution"); return 0;}
        for(int i=1, t; i<=ans[0]; i++) t = ans[i], printf("%d %d %d
    ", e[t].u, e[t].v, e[t].c);
    }
  • 相关阅读:
    Yii2 在模块modules间跳转时,url自动加模块名
    PHP 变量的间接引用(将某一字符串转化为变量)
    windows鼠标悬停任务栏 延迟时间 修改
    dede 常用标签和调用方法汇总
    dedecms ---m站功能基础详解
    apache 2.2 和2.4 目录权限访问设置的区别
    apache httpd.conf 配置局域网访问
    ajax php 点击加载更多
    dede调用当前栏目名 、dede sql
    dede 添加 栏目缩略图
  • 原文地址:https://www.cnblogs.com/candy99/p/6595978.html
Copyright © 2011-2022 走看看