[CODEVS2603]公路修建

题目描述

某国有n个城市,它们互相之间没有公路相通,因此交通十分不便。为解决这一“行路难”的问题,政府决定修建公路。修建公路的任务由各城市共同完成。
    修建工程分若干轮完成。在每一轮中,每个城市选择一个与它最近的城市,申请修建通往该城市的公路。政府负责审批这些申请以决定是否同意修建。
    政府审批的规则如下:
    (1)如果两个或以上城市申请修建同一条公路,则让它们共同修建;
    (2)如果三个或以上的城市申请修建的公路成环。如下图,A申请修建公路AB,B申请修建公路BC,C申请修建公路CA。则政府将否决其中最短的一条公路的修建申请;

    (3)其他情况的申请一律同意。
    一轮修建结束后,可能会有若干城市可以通过公路直接或间接相连。这些可以互相:连通的城市即组成“城市联盟”。在下一轮修建中,每个“城市联盟”将被看作一个城市,发挥一个城市的作用。
    当所有城市被组合成一个“城市联盟”时,修建工程也就完成了。
    你的任务是根据城市的分布和前面讲到的规则,计算出将要修建的公路总长度。

输入输出格式

输入格式:

第一行一个整数n,表示城市的数量。(n≤5000)
  以下n行,每行两个整数x和y,表示一个城市的坐标。(-1000000≤x,y≤1000000)

输出格式:

一个实数,四舍五入保留两位小数,表示公路总长。(保证有惟一解)

输入输出样例

输入样例#1:

4
0 0
1 2
-1 2
0 4

输出样例#1:

6.47

说明

修建的公路如图所示:图放不上去

思路

  做最小生成树的题一直在用克鲁斯卡尔,然而这个题遇到麻烦了。K的贪心选边并不适用,换句话说这就是一道很裸的PRIM的最小树。至于什么环啊压根没有考虑。

  但是,本题还有其特殊性。本题是在Euclid空间求最小生成树,Euclid空间最小生成树有O(nlog2n)的算法,是用Voronoi图+Kruskal算法(或用Prim+heap代替Kruskal)实现的。

var a:array[0..10000,0..10000]of real;
    d:array[0..5000]of real;
    f:array[0..5000]of boolean;
    x,y:array[0..5000]of longint;
    i,j,k,n:longint;
    ans,min:real;

begin
    readln(n);
    for i:=1 to n do
        readln(x[i],y[i]);
    for i:=1 to n do
        for j:=1 to n do
            begin
                a[i,j]:=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
                a[j,i]:=a[i,j];
            end;
    for i:=2 to n do d[i]:=a[1,i];
    f[1]:=true;
    for i:=1 to n-1 do  
        begin
            min:=maxlongint;
            k:=0;
            for j:=2 to n do if (not f[j])and(d[j]<min) then
                begin
                    min:=d[j];
                    k:=j;
                end;
            f[k]:=true;
            ans:=ans+d[k];
            for j:=2 to n do if (not f[j])and(d[j]>a[j,k]) then d[j]:=a[j,k];
    end;
    writeln(ans:0:2);
end.
View Code

 

你可能感兴趣的:([CODEVS2603]公路修建)