欲望以提升热忱,毅力以磨平高山!|

XichenOC

园龄:1个月粉丝:4关注:0

2025-01-20 19:26阅读: 3评论: 0推荐: 0

P3623 [APIO2008] 免费道路

P3623 [APIO2008] 免费道路

题目翻译:

给定一个无向联通图,图中的边有两种类型\(1\)\(0\),求生成一棵树使得类型为\(0\)的边要为\(k\)个。

思路:

阅读题目发现,最后的图要是一棵树,使得上面边为\(0\)的个数为\(k\),我们可以想到先找到,\(k\)个边在找其他边,但又要满足图的联通,那我们运用最小生成树\(kruskal\)算法的思想,先将类型为\(1\)的边给进行加边,若继续加类型\(0\)的边,那这些边就是一定需要的,不管这么搭配,这些边就是必要的。那第二次跑\(kruskal\)时就先加剩下需要的类型为\(0\)的边,直到数量满足为\(k\)时停止,然后加类型为\(1\)的边直至联通。

无解判定:

1.若第一次跑\(kruskal\)时发现必须的边数超过了\(k\)那必然无解
2.若第二次跑完\(kruskal\)时发现无法组成一棵树,或总共加入的类型为零的边不及\(k\)个,则无解

完整代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int fa[N];
int n,m,k,cnt;
struct edge{
    int u,v,w;
}e[N];
bool cmp1(edge x,edge y){
    return x.w<y.w;
}
bool cmp2(edge x,edge y){
    return x.w>y.w;
}
int find(int x){
    if(fa[x]==x)return x;
    else return fa[x]=find(fa[x]);
}
void kruskal1(){
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    sort(e+1,e+1+m,cmp1);
    for(int i=1;i<=m;i++){
        int u=find(e[i].u);
        int v=find(e[i].v);
        if(u!=v){
            fa[u]=v;
            if(e[i].w==1){
                cnt++;
                e[i].w=3;
            }
        }
    }
    if(cnt>k){
        cout<<"no solution"<<endl;
        exit(0);
    }
}
void kruskal2(){
    int num=0;
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    sort(e+1,e+1+m,cmp2);
    for(int i=1;i<=m;i++){
        int u=find(e[i].u);
        int v=find(e[i].v);
        if(find(u)!=find(v)){
            if(e[i].w==1 && cnt==k){
                continue;
            }
            num++;
            fa[u]=v;
            if(e[i].w==1 && cnt<k){
                e[i].w=3;
                cnt++;
            }
            else if(e[i].w==0){
                e[i].w=-2;
            }
        }
    }
    if(num<n-1 || cnt<k){
        cout<<"no solution"<<endl;
        exit(0);
    }
    for(int i=1;i<=m;i++){
        if(e[i].w==3)cout<<e[i].u<<" "<<e[i].v<<" "<<0<<endl;
        if(e[i].w==-2)cout<<e[i].u<<" "<<e[i].v<<" "<<1<<endl;
    }
}
signed main(){
    
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        w=!w;
        e[i]={u,v,w};
    }
    kruskal1();
    kruskal2();
}

最小生成树\(kruskal\)讲解

本文作者:XichenOC

本文链接:https://www.cnblogs.com/XichenOC/p/18682384

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   XichenOC  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起