【问题描述】
给出N个顶点、E条边的连通无向简单图,请你完成下列任务:
任务1、求边权和最小的生成树(最小生成树)
任务2、求边权和最大的生成树(最大生成树)
任务3、求最大边最小的生成树(瓶颈生成树)
任务4、求最小边最大的生成树(瓶颈生成树)
【输入格式】
第一行:两个整数N,E(N<=50000,E<=100000),分别表示有N个新岛,E对能直接用电缆连接的岛屿,其中主岛为1。
接下来M行:每行三个数u,v,w,1<=u,v<=N,表示岛屿u和v之间可以直接用电缆连接,距离为w(<=100000)。
【输出格式】
第一行一个整数,表示最小生成树的边权和;
第二行一个整数,表示最大生成树的边权和;
第三行一个整数,表示最大边最小的生成树中,最大边的权值;
第四行一个整数,表示最小边最大的生成树中,最小边的权值;
【输入样例】
5 8
1 2 2
1 3 12
1 4 10
2 3 8
2 5 9
3 4 6
3 5 3
4 5 7
【输出样例】
19
39
8
8
【数据范围】
N<=50000,E<=100000
用并查集的方法,用贪心的思想从一头开始加边。
详见代码解释:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=50005;
struct shu
{
int u,v,w;
};
vector<shu>g;
int n,m,fa[maxn];
bool my(shu a,shu b)
{
return a.w<b.w;
}
void init()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
g.push_back((shu){x,y,z});
}
sort(g.begin(),g.end(),my);
}
void in()
{
for(int i=0;i<=n;i++)
fa[i]=i;
}
int find(int x)
{
if(fa[x]==x)
return x;
fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
//freopen("in.txt","r",stdin);
init();
in();
int t=n-1;
int ans=0,q;
for(int i=0;i<g.size();i++)
{
if(find(g[i].u)==find(g[i].v)) continue;//如果已经连通就不用加边了。
fa[find(g[i].u)]=find(g[i].v);
t--;//只加n-1条边。
ans+=g[i].w;
if(t==0)
{
q=g[i].w;//最后一条边一定是最大的。
break;
}
}
printf("%d\n",ans);
t=n-1;
ans=0;
int p;
in();
for(int i=g.size()-1;i>=0;i--)
{
if(find(g[i].u)==find(g[i].v)) continue;
fa[find(g[i].u)]=find(g[i].v);
t--;
ans+=g[i].w;
if(t==0)
{
p=g[i].w;
break;
}
}
printf("%d\n%d\n%d",ans,q,p);
return 0;
}