- 题目大意
给一个图,求改图的生成树的最大边的最小值。
- 分析
二分该最大边的值,lgE的复杂度。剩下就是判断是否满足最大边限制的最小生成树了。kruskal的做法就是先将该边加入到集合,在依次加边的时候如果当前边大于该最大变则表示以该边为最大值的生成树不存在 - 代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
const int INF=999999999;
int T;
int n;
int mapp[600][600];
int pa[600];
struct Edge
{
int u;
int v;
int d;
}edge[502*502];
int edgenum=0;
int Cmp(const void *p1,const void *p2)
{
return ((Edge *)p1)->d - ((Edge *)p2)->d;
}
int Find(int x)
{
return x==pa[x] ? x : x=Find(pa[x]);
}
void Union(int a,int b)
{
int xa=Find(a);
int xb=Find(b);
if(xa!=xb)pa[xa]=xb;
}
void Add_Edge(int u,int v,int d)
{
edge[++edgenum].u=u;
edge[edgenum].v=v;
edge[edgenum].d=d;
}
bool Kruskal(int x)//edge[x].d表示最小生成树中的最大值 可以返回1
{
for(int i=1;i<=n;i++)pa[i]=i;
int cnt=1;
int max_edge=edge[x].d;
Union(edge[x].u,edge[x].v);
for(int i=1;i<=edgenum;i++)
{
if(i==x)continue;
if(edge[i].d>edge[x].d)return 0;
if(Find(edge[i].u)!=Find(edge[i].v))
{
Union(edge[i].u,edge[i].v);
cnt++;
if(cnt==n-1)
{
return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d",&T);
while(T--)
{
edgenum=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&mapp[i][j]);
Add_Edge(i,j,mapp[i][j]);
}
}
qsort(edge+1,edgenum,sizeof(Edge),Cmp);
int L=1;
int R=edgenum;
int M;
while(L<R)
{
M=(L+R)/2;
if(Kruskal(M))R=M;
else
{
if(L==R-1)L=R;
else L=M;
}
}
printf("%d\n",edge[L].d);
}
}