2018.11.02【校內模擬】飛越行星帶(最小生成樹)

傳送門


解析:

最小生成樹的優秀做法。

建圖很妙啊,把所有點對之間建立距離爲權值的邊,然後所有點向頂部連權值爲距離的邊,向底部連權值爲LyL-y的邊,然後求一個最小生成樹,將頂部和底部連在一起的邊的權值就是答案。

我解釋一下爲什麼這樣做是對的。
考慮我們現在有一艘直徑爲當前枚舉邊的飛碟,我們禁止它通過這條邊,如果它還可以飛到另一端,說明它穿過了一些權值大於它的直徑的邊,那麼它的直徑可以繼續增大。而上下連在一起,就形成了一個圍欄,它就永遠不可能到達另一端。此時它的直徑就已經達到了最大。


代碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	re bool f=0;
	while(!isdigit(c=gc()))if(c=='-')f=1;num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return f?-num:num;
}

cs int N=502;
struct edge{
	int u,v;
	double w;
	friend bool operator<(cs edge &a,cs edge &b){
		return a.w<b.w;
	}
}E[N*N];int ecnt;

inline void addedge(int u,int v,double w){
	E[++ecnt]=(edge){u,v,w};
}

int fa[N];
inline int getfa(int u){
	while(u^fa[u])u=fa[u]=fa[fa[u]];
	return u;
}

int n,L;
int x[N],y[N];
inline double dist(int i,int j){
	return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}

signed main(){
	n=getint();L=getint();
	for(int re i=1;i<=n;++i){
		fa[i]=i;
		x[i]=getint();y[i]=getint();
		for(int re j=1;j<i;++j)addedge(i,j,dist(i,j));
		addedge(0,i,y[i]);
		addedge(n+1,i,L-y[i]);
	}
	fa[n+1]=n+1;
	sort(E+1,E+ecnt+1);
	for(int re i=1;i<=ecnt;++i){
		int u=getfa(E[i].u);
		int v=getfa(E[i].v);
		if(u==v)continue;
		fa[v]=u;
		if(getfa(0)==getfa(n+1)){
			printf("%.3f",E[i].w);
			return 0;
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章