【洛谷P2504】聪明的猴子 最小瓶颈树

题目大意:给定一张 N 个顶点的完全图,边有边权,求该完全图的一棵最小瓶颈树。

最小瓶颈树:一棵最大边权值在同一张图的所有生成树中最小,即:最大边权值最小的生成树,其值为该树的最大边权的权值。
引理1:最小生成树一定是一棵最小瓶颈树。
证明:若最小生成树不是最小瓶颈树,则意味着存在一条边的权值大于最小瓶颈树的最大边权值,那么将 MST 的该边去掉,则将一棵树变成了不连通的两棵树,再将最小瓶颈树的一条连接这两个联通块的边加入 MST,可以得到一棵权值更小的生成树,与 MST 性质矛盾,证毕。

引理2:最小瓶颈树不一定是最小生成树。
证明:证明

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxe=1e6+10;
const int maxv=1010;

inline int read(){
	int x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}

int n,m,tot,d[maxv>>1],f[maxv],sum,path,cnt;
struct node{int x,y;}p[maxv];
struct edge{int from,to,w;}e[maxe];

bool cmp(const edge& x,const edge& y){return x.w<y.w;}

inline int get_dis(int a,int b){
	return (p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y);
}

void read_and_parse(){
	m=read();
	for(int i=1;i<=m;i++)d[i]=read();
	sum=n=read();
	for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			e[++tot]=edge{i,j,get_dis(i,j)};
}

int find(int x){return x==f[x]?f[x]:f[x]=find(f[x]);}

int kruskal(){
	int src;
	for(int i=1;i<=n;i++)f[i]=i;
	sort(e+1,e+tot+1,cmp);
	for(int i=1;i<=tot&&sum>1;i++){
		int x=find(e[i].from),y=find(e[i].to);
		if(x==y)continue;
		f[x]=y,--sum,src=e[i].w;
	}
	return src;
}

void solve(){
	path=kruskal();
	for(int i=1;i<=m;i++)if(d[i]*d[i]>=path)++cnt;
	printf("%d
",cnt);
}

int main(){
	read_and_parse();
	solve();
	return 0;
} 
原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10062776.html