題解 P1991 【無線通信網】

題目node

這一題對我有歷史性的意義,由於我深入意識到:c++

不要用namespace!算法

不要用namespace!spa

不要用namespace!code

寫此題解,以示他人。get

(搞錯重點了吧喂!)it


好,迴歸正題:io

這道題的思路是這樣:模板

首先,用Kruskal算法。class

(建議先把 並查集模板與 最小生成樹模板 打了再繼續看)

咱們回顧一下Kruskal算法的過程:

把邊按權值從小到大一條條排好,而後再從未選擇的點中添加邊,一直添加到節點數-1爲止。

重點:爲何是節點數-1?由於最小生成樹要讓圖連通。

可不能夠不連通?

能夠!

該題中,衛星電話的存在,就是爲了能夠讓圖斷開。而最後求的最大邊,就是最後一個添加到圖中的邊。

附上代碼:

#include <bits/stdc++.h>
#define MAXN 200005
int node,edgenum=0,ans=0,k=0,s;
int fat[MAXN],siz[MAXN];
//座標 
struct pair
{
	int first,second;
}	a[MAXN];
//圖 
struct EDGE
{
	int from,to;double cost;
}	e[MAXN];
//比較器 
bool cmp(EDGE a,EDGE b)	{return a.cost<b.cost;}
//並查集 + 路徑壓縮 + 啓發式搜索 
int Find(int x){ return (fat[x]==x)? x : fat[x]=Find(fat[x]); }
void unionn(int x,int y){
	x=Find(x); y=Find(y);
	if(siz[x]>siz[y])	std::swap(x,y);
	fat[x]=y;	siz[y]+=siz[x]; 
}
//兩點之間距離公式 
double distance(pair m , pair n)
{
	double ans=std::sqrt( (m.first-n.first)*(m.first-n.first) + (m.second-n.second)*(m.second-n.second) );
	return ans;
}

int main()
{
	double d;
	std::scanf("%d%d",&s,&node);
	for(int i=1;i<=node;++i)	scanf("%d%d",&a[i].first,&a[i].second);
	for(int i=1;i<=node;++i)	{fat[i]=i;	siz[i]=1;}	//初始化 
	for(int i=1;i<=node;++i)	//構圖 
	{
		for(int j=i+1;j<=node;++j)
		{
			e[ ++edgenum ].from=i;	e[ edgenum ].to=j;
			e[ edgenum ].cost=distance(a[i],a[j]);
		}
	}
	//	Kurskal 
	std::sort(e+1,e+edgenum+1,cmp);
	for(int i=1;i<=edgenum;++i)
	{
		if(k==node-s) break;//節點數-衛星電話數
		if(Find(e[i].from) != Find(e[i].to))
		{
			unionn(e[i].from,e[i].to); 
			d=e[i].cost;	++k; 
		}
	}		
	std::printf("%.2lf",d);
	return 0;
}

其實這題的數據有點弱。

個人代碼是有缺陷的,但是AC了。

應該還要再添加一些特判。

好比,當衛星電話數大於節點數時,d應該爲0。

當衛星電話數爲0時,應該與衛星電話爲1時的狀況相等。

相關文章
相關標籤/搜索