北極通訊網路——最小生成樹kruskal

mashizuren發表於2020-12-05

北極的某區域共有 n 座村莊,每座村莊的座標用一對整數 (x,y) 表示。為了加強聯絡,決定在村莊之間建立通訊網路。通訊工具可以是無線電收發機,也可以是衛星裝置。所有的村莊都可以擁有一部無線電收發機, 且所有的無線電收發機型號相同。但衛星裝置數量有限,只能給一部分村莊配備衛星裝置。

不同型號的無線電收發機有一個不同的引數 d,兩座村莊之間的距離如果不超過 d 就可以用該型號的無線電收發機直接通訊,d 值越大的型號價格越貴。擁有衛星裝置的兩座村莊無論相距多遠都可以直接通訊。

現在有 k 臺衛星裝置,請你編一個程式,計算出應該如何分配這 k 臺衛星裝置,才能使所擁有的無線電收發機的 d 值最小,並保證每兩座村莊之間都可以直接或間接地通訊。

例如,對於下面三座村莊:

在這裡插入圖片描述

其中 |AB|=10,|BC|=20,|AC|=10√5≈22.36,

如果沒有任何衛星裝置或只有 1 臺衛星裝置 (k=0 或k=1 ),則滿足條件的最小的d=20,因為 A 和 B,B 和 C 可以用無線電直接通訊;而 A 和 C 可以用 B 中轉實現間接通訊 (即訊息從 A 傳到 B,再從 B 傳到 C );

如果有 2 臺衛星裝置 (K=2),則可以把這兩臺裝置分別分配給 B 和 C ,這樣最小的 d 可取10 ,因為 A 和 B 之間可以用無線電直接通訊;B 和 C 之間可以用衛星直接通訊;A 和 C 可以用 B 中轉實現間接通訊。

如果有 3 臺衛星裝置,則 A,B,C 兩兩之間都可以直接用衛星通訊,最小的 d 可取 0 。

輸入格式
第一行為由空格隔開的兩個整數 n,k;

第 2~n+1 行,每行兩個整數,第 i 行的 xi,yi 表示第 i 座村莊的座標 (xi,yi)。

輸出格式
一個實數d,表示最小的 d 值,結果保留 2 位小數。

樣例輸入:
3 2
10 10
10 0
30 0

樣例輸出:
10.00

北極通訊系統:
題意:有n個村莊,k個衛星裝置,每兩個衛星可以連線兩個村莊,無距離限制,剩餘沒有辦法通訊的村莊需要用無線裝置連線通訊,距離越遠(d越大),成本越高,求最小d。

思路:最小生成樹,求出每條邊的距離即邊權值,k為0和k為1對村莊通訊毫無影響,即對所有n-1條邊進行判斷,當k大於1時,需要判斷n-k條邊。
綜合起來,當k=0時,讓k等於1,只需判斷n-k條邊即可,從最小邊權值開始找,依次增大,找到其中滿足條件的最小的d。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int M=1010;
const int N=1e6+10;
int x[M],y[M],e[M];///
int n,k,s;
double ans;
///結構體儲存兩個村莊和兩個村莊的距離
struct node
{
    int a;
    int b;
    double l;
}qq[N];
///讓距離即邊權值從小到大排序(kruskal演算法)
bool cmp(node x,node y)
{
    return x.l<y.l;
}
int find(int x)
{
    return x==e[x]?x:find(e[x]);
}
void kruskal()
{
    int i,j,t1,t2,sum=0;
    for(i=1;i<=n;i++)
    {
        e[i]=i;///初始化
    }
    for(i=1;i<=s;i++)
    {
        t1=find(qq[i].a);///判斷將要連線的村莊是否在同一條樹枝上
        t2=find(qq[i].b);
        if(t1!=t2)///不在則連線,邊數+1
        {
            e[t1]=t2;
            sum++;
        }
        ///當連線邊數為n-k,表示連線完成,輸出此時的邊長即為最小的d
        if(sum==n-k)///衛星抵消後剩餘邊數
        {
            //ans=sqrt(qq[i].l);
            printf("%.2lf\n",qq[i].l);
            return ;
        }
    }
}
int main()
{
    int i,j,m;
    s=0;
    cin>>n>>k;
    for(i=1;i<=n;i++)
        cin>>x[i]>>y[i];
    for(i=1;i<=n;i++)
    {
        for(j=i+1;j<=n;j++)
        {
            qq[++s].a=i;
            qq[s].b=j;
            qq[s].l=sqrt((x[j]-x[i])*(x[j]-x[i])+(y[j]-y[i])*(y[j]-y[i]));
        }
    }
    if(k==0)
        k=1;
    ///衛星為零個或一個對村莊通訊無影響
    ///此時n-1條邊都需要遍歷
    ///令k為1,使n-k為剩餘遍歷邊數,消除k為零的影響
    sort(qq+1,qq+s+1,cmp);
    kruskal();

    return 0;
}

相關文章