1. 程式人生 > >最小生成樹 (Kruskal演算法)POJ 2349 Arctic Network

最小生成樹 (Kruskal演算法)POJ 2349 Arctic Network

Description

The Department of National Defence (DND) wishes to connect several northern outposts by a wireless network. Two different communication technologies are to be used in establishing the network: every outpost will have a radio transceiver and some outposts will in addition have a satellite channel.  Any two outposts with a satellite channel can communicate via the satellite, regardless of their location. Otherwise, two outposts can communicate by radio only if the distance between them does not exceed D, which depends of the power of the transceivers. Higher power yields higher D but costs more. Due to purchasing and maintenance considerations, the transceivers at the outposts must be identical; that is, the value of D is the same for every pair of outposts. Your job is to determine the minimum D required for the transceivers. There must be at least one communication path (direct or indirect) between every pair of outposts.

Input

The first line of input contains N, the number of test cases. The first line of each test case contains 1 <= S <= 100, the number of satellite channels, and S < P <= 500, the number of outposts. P lines follow, giving the (x,y) coordinates of each outpost in km (coordinates are integers between 0 and 10,000).

Output

For each case, output should consist of a single line giving the minimum D required to connect the network. Output should be specified to 2 decimal points.

Sample Input

1
2 4
0 100
0 300
0 600
150 750

Sample Output

212.13

題意:

有P個站點需要遠端通訊,它們能通過兩種方式來通訊:無線電和衛星. 如果兩個站點通過兩個衛星接收器(坑,每個站點各一個衛星接收器)來通訊的話,它們直接無論多遠都行且不花錢. 如果兩個站點通過無線電來通訊的話,需要花錢且距離越長花費越大. 現在我們只有S個衛星接收器(也就是說這S個站點無論多遠都可以聯絡到,那麼他們的最小生成樹可以把這S個站點看成一個點,從而少了S-1條邊),所以我們現在需要讓通過無線電通訊的站點間的所有距離中的最大值D勁量小.求這個D的可能最小值?  

思路:

假設沒有衛星接收器,我們需要構建一個最小生成樹才能讓圖連通.且這時候的D值肯定是生成樹上的最長邊.如果此時有2個衛星接收器,為了讓D值最小,我們只需要不斷的新增邊然後使得不連通的兩點變成連通,且最終剩下兩個連通分量即可.(這兩個連通分量可以通過衛星連線起來)

       所以其實本題要我們做的是,把所有的邊依次新增進去,每次新增邊都使得兩個點連通,當新增到全圖還剩S個連通分量時就行.因為這S個連通分量會通過衛星連線起來. 在新增邊的過程中,我們希望D值最小,即我們新增的邊中邊長最大的那條邊要最小,我們如何做到呢?

       我們只需要把所有邊排序,然後從小到大進行處理.如果當前的邊可以使得兩個不同分量的點連線,就新增,否則不新增.這樣我們新增的最大長度的邊長一定最小.

證明:假設存在更優的解即邊集合{e1,e2…ei}使得整個圖還剩S個連通分量,且該邊集合的最長邊要比我們上訴做法得到的最長邊短. 其實可以看出只要存在一個這種解,我們上訴的選擇方式一定可以選出該解的,因為我們數從邊長小到大選擇的.

       網上很多解法是求最小生成樹,然後將最長的S-1條邊刪除,然後求當前的最長邊.其實這種解法是不嚴謹的.因為你沒法證明最小生成樹的前S-1條最長邊刪除之後得到的S個連通分量後,這些分量中最長邊的值最小(除非你生成最小生成樹的時候是從小到大選邊的).甚至其實最小生成樹與本題關注的都不是同一個問題.只是碰巧能通過最小生成樹刪除邊來解罷了.  

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
struct point
{
    double x,y;
}points[250010];
struct edge
{
    int u,v;
    double dist;
    edge(int x,int y,double d):u(x),v(y),dist(d){}
    edge(){}
    bool operator<(const edge &edg)const
    {
        return dist<edg.dist;
    }
}edges[250010];
int fa[250010];
int findest(int u)   //並查集
{
    if(fa[u]==-1)return u;
    else
    {
        fa[u]=findest(fa[u]);
    }
    return fa[u];
}
double getdist(int i,int j)
{
    double x1=points[i].x;
    double y1=points[i].y;
    double x2=points[j].x;
    double y2=points[j].y;
    double dis=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    return dis;
}
int main()
{
    int t;
    cin>>t;
    int s,n;
    while(t--)
    {
        memset(fa,-1,sizeof(fa));
        cin>>s>>n;
        for(int i=0;i<n;i++)
        {
            cin>>points[i].x>>points[i].y;
        }
    int cnt=0;
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++)
    {
        edges[cnt++]=edge(i,j,getdist(i,j));
    }
    sort(edges,edges+cnt);
    int num=0;
    double sss;
    for(int i=0;i<cnt;i++)
    {
        int u1=edges[i].u;
        int v1=edges[i].v;
        if(findest(u1)!=findest(v1))  //不存在一個環、。
        {
            fa[findest(u1)]=findest(v1);
            num++;
            if(num==n-s)
            {
                sss=edges[i].dist;
                break;
            }
        }
    }
    //cout<<sss<<endl;
    printf("%.2lf\n",sss);
}
return 0;  //在poj上因為沒有加return 0;W了
}