近期在玩SIMCITY5(详细资料找百度吧),各种坑爹之处就不说了,但是有一个问题却很有意思——天桥。
此天桥非彼天桥,SIMCITY5里的天桥是用于连接Megatower(巨塔)使得各个Megatower间连通的利器,可以有效缓解交通压力(毕竟Megatower人口容量巨大)。但是,天桥的造价真的是“天价”,要是真的没有什么钱又想把Megatower都连接起来该怎么办呢?
先看下面这个模型
在这个模型里,我们把Megatower简化成了一个一个的点。从图中可以很清晰地看见每两个点之间的距离。由于天桥每单位距离的造价相同,想要让总造价最小其实就是让修建的距离最小。而又因为我们要让总距离最小,我们修建的天桥不可能形成一个环,所以其实我们要求的就是最小生成树。这时我们就可以用上Kruskal大法了。
Kruskal会教你这么做(初始化:定义n(n是指Megatower个数,这一例子中n=4)个点集,每个点集代表和这个点相连的点,刚开始只有一个点,如s1={1},s2={2},……,sn={n},等)
1.第一步,由于AB间距离最短,我们可以优先在这两座Megatower间修建一座天桥。
此时sA={A,B},sB={},sC和sD不变
2.之后,我们再找一条最短边,此时AC=sqrt(2)最短,于是连接AC,sA={A,B,C},sC={}
3.然后我们来找下一条最短边,此时BC=AD=sqrt(5)。我们要连哪条边呢?这时我们要看看集合S,上面说了,sA={A,B,C},那么我们就没有必要连接BC了。我们的最终目标只是把Megatower都连起来,没有必要多建天桥(除非你的城市交通压力大过头了),我们把BC连起来只会浪费城市资金。于是选择连接AD(图就不画了吧)。此时sA={A,B,C,D},sD={},由于sA已包含所有的Megatower,也就代表着所有的Megatower都已被连接起来,算法结束。
当然,有些时候数据很大,此时集合S可以用并查集优化,用以增大集合容量。用时只需把要连接的两个点所在的树合并即可。
核心代码如下(无视这恶心的缩进吧……):
procedure kruskal;
var p:longint;
begin
sum:=0;
p:=1;//连了几条边,当p=n-1时算法成功
while p<=n-1 do
begin
for i:=1 to e do
begin
if find(edg[i].u)<>find(edg[i].v) then//两个点不在同一集合内
begin
inc(p);
sum:=sum+edg[i].w;
if p=n then begin writeln(sum); halt; end;
union(edg[i].u,edg[i].v); //合并两个点所在的树
end;
end;
end;
end;