最小生成树模板题 P1692

Description

给出N个顶点、E条边的连通无向简单图,请你完成下列任务: 任务1、求边权和最小的生成树(最小生成树) 任务2、求边权和最大的生成树(最大生成树) 任务3、求最大边最小的生成树(瓶颈生成树) 任务4、求最小边最大的生成树(瓶颈生成树)

Input

第一行:两个整数N,E(N<=50000,E<=100000),分别表示有N个新岛,E对能直接用电缆连接的岛屿,其中主岛为1。接下来M行:每行三个数u,v,w,1<=u,v<=N,表示岛屿u和v之间可以直接用电缆连接,距离为w(<=100000)。

Output

第一行一个整数,表示最小生成树的边权和;第二行一个整数,表示最大生成树的边权和;第三行一个整数,表示最大边最小的生成树中,最大边的权值;第四行一个整数,表示最小边最大的生成树中,最小边的权值;

Hint

N<=50000,E<=100000

Solution

注意事项: 1.这个就像有向图那么存就可以了不然排序可能有边排不到,不然用2*m应该也行吧。 2.循环注意=号。 3.并查集的union修改的是父亲的值,如果只修改x,y的值父亲的值就没有被修改到。 4.应该是要用long long的只不过数据太弱了。
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define maxn 100005
#define inf 0x3f3f3f3f
using namespace std;
struct Edge{
    int u;
    int v;
    int w;
    int next;
    friend bool operator < (Edge a,Edge b){
        return a.w<b.w;
    }
}edge[maxn];
int first[maxn],last[maxn],FA[maxn];
int node,n,m,x,y,z,cnt;
int ans1,ans2,ans3,ans4;
void addedge(int u,int v,int w){
    edge[++node]=(Edge){u,v,w,0};
    if(first[u]==0)first[u]=node;
    else edge[last[u]].next=node;
    last[u]=node;
}
void init(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y,z);
    }
    for(int i=1;i<=n;i++){
        FA[i]=i;
    }
}
int dofind(int x){
    if(FA[x]==x)return x;
    return FA[x]=dofind(FA[x]);
}
void dounion(int x,int y){
    int dx=dofind(x),dy=dofind(y);
    if(dx!=dy){
        FA[dx]=FA[dy];
    }
}
bool dofinD(int x,int y){
    int dx=dofind(x),dy=dofind(y);
    return dx==dy;
}
void kruskal(){
    sort(edge+1,edge+m+1);
    for(int i=1;i<=m;i++){
        int a=edge[i].u,b=edge[i].v;
        if(dofinD(a,b))continue;
        dounion(a,b);
        ans1+=edge[i].w;
        ans2=edge[i].w;
        cnt++;
        if(cnt==n-1)break;
    }
    cnt=0;
    for(int i=1;i<=n;i++){
        FA[i]=i;
    }
    for(int i=m;i>=1;i--){
        int a=edge[i].u,b=edge[i].v;
        if(dofinD(a,b))continue;
        dounion(a,b);
        ans3+=edge[i].w;
        ans4=edge[i].w;
        cnt++;
        if(cnt==n-1)break;
    }
}
int main(){
    init();
    kruskal();
    printf("%d\n%d\n%d\n%d\n",ans1,ans3,ans2,ans4);
    return 0;
}

转载于:https://www.cnblogs.com/virtual-north-Illya/p/10045223.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值