整理的算法模板:ACM算法模板總結(分類詳細版)
北極的某區域共有 nn 座村莊,每座村莊的座標用一對整數 (x,y)(x,y) 表示。
爲了加強聯繫,決定在村莊之間建立通訊網絡,使每兩座村莊之間都可以直接或間接通訊。
通訊工具可以是無線電收發機,也可以是衛星設備。
無線電收發機有多種不同型號,不同型號的無線電收發機有一個不同的參數 dd,兩座村莊之間的距離如果不超過 dd,就可以用該型號的無線電收發機直接通訊,dd 值越大的型號價格越貴。現在要先選擇某一種型號的無線電收發機,然後t統一給所有村莊配備,數量不限,但型號都是 相同的。
配備衛星設備的兩座村莊無論相距多遠都可以直接通訊,但衛星設備是 有限的,只能給一部分村莊配備。
現在有 kk 臺衛星設備,請你編一個程序,計算出應該如何分配這 kk 臺衛星設備,才能使所配備的無線電收發機的 dd 值最小。
例如,對於下面三座村莊:
其中,|AB|=10,|BC|=20,|AC|=105√≈22.36|AB|=10,|BC|=20,|AC|=105≈22.36。
如果沒有任何衛星設備或只有 11 臺衛星設備 (k=0k=0 或 k=1k=1),則滿足條件的最小的 d=20d=20,因爲 AA 和 BB,BB 和 CC 可以用無線電直接通訊;而 AA 和 CC 可以用 BB 中轉實現間接通訊 (即消息從 AA 傳到 BB,再從 BB 傳到 CC);
如果有 22 臺衛星設備 (k=2k=2),則可以把這兩臺設備分別分配給 BB 和 CC ,這樣最小的 dd 可取 1010,因爲 AA 和 BB 之間可以用無線電直接通訊;BB 和 CC 之間可以用衛星直接通訊;AA 和 CC 可以用 BB 中轉實現間接通訊。
如果有 33 臺衛星設備,則 A,B,CA,B,C 兩兩之間都可以直接用衛星通訊,最小的 dd 可取 00。
輸入格式
第一行爲由空格隔開的兩個整數 n,kn,k;
接下來 nn 行,每行兩個整數,第 ii 行的 xi,yixi,yi 表示第 ii 座村莊的座標 (xi,yixi,yi)。
輸出格式
一個實數,表示最小的 dd 值,結果保留 22 位小數。
數據範圍
1≤n≤5001≤n≤500,
0≤x,y≤1040≤x,y≤104,
0≤k≤1000≤k≤100
輸入樣例:
3 2
10 10
10 0
30 0
輸出樣例:
10.00
思路:
首先既然有k個衛星可以用,那麼我們儘可能的將衛星用於連接k個連通塊;剛開始有n個連通塊,用kruskal算法從小到大處理所有邊,每次記錄當前連通塊剩餘個數res,當res==k時,就可以用衛星將所有的連通塊連接起來;類似於貪心的思想,這樣的到的一定是最小的;
#include <bits/stdc++.h>
using namespace std;
const int N=505,M=505*505;
int x[N],y[N],cnt,p[N],n,k;
struct node
{
int a,b;
double dis;
}e[M];
bool cmp(node a,node b)
{
return a.dis<b.dis;
}
double get(int a,int b,int c,int d)
{
return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}
int find(int x)
{
if(p[x]!=x)
{
p[x]=find(p[x]);
}
return p[x];
}
double kruskal()
{
double res=0;
for(int i=0;i<=n;i++) p[i]=i;
for(int i=0;i<cnt;i++)
{
if(n<=k) return res;
int a=find(e[i].a),b=find(e[i].b);
if(a!=b)
{
p[a]=b;
n--;
res=e[i].dis;
}
}
return res;
}
int main()
{
cin >>n>>k;
for(int i=0;i<n;i++) cin >>x[i]>>y[i];
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
double dis=get(x[i],y[i],x[j],y[j]);
e[cnt++]={i,j,dis};
}
}
sort(e,e+cnt,cmp);
printf("%.2f",kruskal());
}