[BZOJ 3624][Apio2008]免费道路:最小生成树

点击这里查看原题

由题目要求可知,最终得到的图是一棵树。因为要求类型为0的边恰好有k条,所以先对类型为1的边做生成树,再对类型为0的边做,得到必须有的0边。将这些0边加入,然后优先做类型为0的边,再做类型为1的边即可

/*
User:Small
Language:C++
Problem No.:3624
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=1e5+5,N=2e4+5;
int n,m,k,tp,s[N],u[M],v[M],c[M],num[2],pre[N];
bool mark[M];
int find(int x){
    return x==pre[x]?x:pre[x]=find(pre[x]);
}
void solve(bool typ,int cnt){
    for(int i=1;i<=m;i++){
        if(c[i]==typ&&num[typ]<cnt){
            int p=find(u[i]),q=find(v[i]);
            if(p==q) continue;
            pre[p]=q;
            num[typ]++;
            s[++tp]=i;
            mark[i]=1;
        }
    }
}
int main(){
    freopen("data.in","r",stdin);//
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&u[i],&v[i],&c[i]);
    for(int i=1;i<=n;i++) pre[i]=i;
    solve(1,inf);solve(0,inf);
    if(num[0]+num[1]!=n-1||num[0]>k){
        printf("no solution\n");
        return 0;
    }
    tp=num[0]=num[1]=0;
    for(int i=1;i<=n;i++) pre[i]=i;
    for(int i=1;i<=m;i++){
        if(c[i]==0&&mark[i]){
            int p=find(u[i]),q=find(v[i]);
            if(p==q) continue;
            pre[p]=q;
            s[++tp]=i;
            num[0]++;
        }
    }
    solve(0,k);solve(1,inf);
    if(num[0]<k){
        printf("no solution\n");
        return 0;
    }
    for(int i=1;i<=tp;i++)
        printf("%d %d %d\n",u[s[i]],v[s[i]],c[s[i]]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值