题意:
CSP201812-4.
思路:
首先阅读题目,了解题意,知道是给定无向图,求解一棵生成树,使得Tmax最小。而根据题目,Tmax即树上边权的最大值。也就是说,要求出最小瓶颈生成树。利用性质:最小生成树一定是最小瓶颈生成树。最后我们要做的就是求出最小生成树,然后输出最大边。
使用kruskal求最小生成树。求最短边用到了小根堆,STL中的小根堆要有自定义的排序结构cmp,且应重载’( )’。判断要加入的边是否组成环路用到了并查集。因为题目一定满足有最小生成树,于是直接取了n-1条边,然后用ans来记录最大边的权值。
总结:
CSP201812-4,一道看起来很难的题,但是知道了思路就很好实现。但是求最小生成树的思路并不好想。题目中所给的root并没有用,也就是说要学得从题目中读取有用条件的本领,不然看到这么长的题目会头皮发麻。同时kruskal求最小生成树要熟练掌握。
代码:
#include <iostream>
#include <queue>
using namespace std;
int n,m,root;
int ans=0;
//并查集
int par[50001],rnk[50001];
void init(int n)
{
for(int i=1; i<=n; i++)
par[i]=i,rnk[i]=1;
}
int find(int x)
{
return par[x]==x?x:par[x]=find(par[x]);
}
bool unite(int x,int y)
{
x=find(x),y=find(y);
if(x==y) return false;
if(rnk[x]>rnk[y])
par[y]=x,rnk[x]=(rnk[y]+=rnk[x]);
else
par[x]=y,rnk[y]=(rnk[x]+=rnk[y]);
return true;
}
struct edge
{
int v,w,z;
edge(int v1=0,int w1=0,int z1=0)
{
v=v1,w=w1,z=z1;
}
};
edge e[100001]; //从1开始
struct cmp
{
bool operator () (edge a,edge b)
{
return a.z>b.z; //小根堆用大于号
}
};
priority_queue<edge,vector<edge>,cmp> pq; //小根堆
void kruskal()
{
//向小根堆中添加所有的边,应避免重复加入
for(int i=1; i<=m; i++)
pq.push(e[i]);
//并查集初始化
init(n);
for(int i=0; i<n-1; i++) //共取n-1条边
{
edge theEdge=pq.top();
pq.pop();
int a=theEdge.v,b=theEdge.w;
if(find(a)!=find(b)) //不构成环路
{
if(ans<theEdge.z)
ans=theEdge.z;
unite(a,b);
}
else i--;
}
cout<<ans<<endl;
}
int main()
{
cin>>n>>m>>root;
for(int i=1;i<=m;i++)
{
int v,w,z;
cin>>v>>w>>z;
e[i].v=v,e[i].w=w,e[i].z=z;
}
kruskal();
}