最小生成树——联络员 Kruskal

题目描述

Tyvj 已经一岁了,网站也由最初的几个用户增加到了上万个用户,随着 Tyvj 网站的逐步壮大,管理员的数目也越来越多,现在你身为 Tyvj 管理层的联络员,希望你找到一些通信渠道,使得管理员两两都可以联络(直接或者是间接都可以)。Tyvj 是一个公益性的网站,没有过多的利润,所以你要尽可能的使费用少才可以。

目前你已经知道,Tyvj 的通信渠道分为两大类,一类是必选通信渠道,无论价格多少,你都需要把所有的都选择上;还有一类是选择性的通信渠道,你可以从中挑选一些作为最终管理员联络的通信渠道。数据保证给出的通行渠道可以让所有的管理员联通

输入格式:

第一行 n,m 表示 Tyvj 一共有 n 个管理员,有 m 个通信渠道

第二行到 m+1 行,每行四个非负整数,p,u,v,w 当 p=1 时,表示这个通信渠道为必选通信渠道;当 p=2 时,表示这个通信渠道为选择性通信渠道;u,v,w 表示本条信息描述的是 u,v 管理员之间的通信渠道,u 可以收到 v 的信息,v 也可以收到 u 的信息,w 表示费用。

输出格式:

最小的通信费用

由于我个人prim用的比较熟所以刚开始做这道题一直企图用prim把它解出来,但是经过一番云雨,我发现prim根本不适合解这道题(╥╯^╰╥),反而用我不是很熟的Kruskal解很快就解出来了。大体思路就是先把必选路径放入最小生成树,然后再找剩下的选择性路径,最后找出最终的最小生成树。

Kruskal代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct data
{
    int x,y,v;
}e[20001];
int n,m,father[2001],cnt,ans;
int find(int x)
{
    return x==father[x]? x:father[x]=find(father[x]);
}
 bool cmp(data a,data b)
{
    return a.v<b.v;
}
void un(int x,int y,int v)
{
     father[find(x)]=find(y);
     ans+=v;
}
void insert(int x,int y,int v)
{
     cnt++;
     e[cnt].x=x;e[cnt].y=y;
     e[cnt].v=v;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    father[i]=i;
    for(int i=1;i<=m;i++)
    {
        int flag,x,y,v;
        cin>>flag>>x>>y>>v;
        if(flag==1)un(x,y,v);
        else insert(x,y,v);
    }
    sort(e+1,e+cnt+1,cmp);
    for(int i=1;i<=cnt;i++)
    {
        int x=find(e[i].x),y=find(e[i].y);
        if(father[x]!=father[y])un(x,y,e[i].v);
    }   
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/wty20010315/p/6719035.html