目录见右上
站内文章欢迎各位转载,但是请注明出处(毕竟码字很辛苦哈)。

主题

1003 电话连线

题目描述 Description

一个国家有n个城市。若干个城市之间有电话线连接,现在要增加m条电话线(电话线当然是双向的了),使得任意两个城市之间都直接或间接经过其他城市有电话线连接,你的程序应该能够找出最小费用及其一种连接方案。

 

输入描述 Input Description

    输入文件的第一行是n的值(n<=100).

    第二行至第n+1行是一个n*n的矩阵,第i行第j列的数如果为0表示城市i与城市j有电话线连接,否则为这两个城市之间的连接费用(范围不超过10000)。

输出描述 Output Description

       输出文件的第一行为你连接的电话线总数m,第二行至第m+1行为你连接的每条电话线,格式为i j,(i<j), i j是电话线连接的两个城市。输出请按照Prim算法发现每一条边的顺序输出,起始点为1.

       第m+2行是连接这些电话线的总费用。

样例输入 Sample Input

5

0 15 27 6 0

15 0 33 19 11

27 33 0 0 17

6 19 0 0 9

0 11 17 9 0

样例输出 Sample Output

2

1 4

2 5

17

数据范围及提示 Data Size & Hint

n<=100


个人解法:

很显然的是Prim。

只是说说需要做的操作怎么实现。

首先,在我们更新最小生成树的时候,会有一条边的权值。这条权值如果是0,则表明这条边是给出的,不必工程费。而如果边权不为0,则说明我们必须要花钱去买。

接下来,对于总权值的计算就是就是所有最小生成树边权加起来。

而对于路径输出,个人是用的数组储存,对于一条权值不为0的边,就记录下来。之后按顺序输出即可。

这么久没有打Prim,复习复习图论。


代码如下:

type

inf=record

      x,y:longint;//一个存边的玩意

     end;


var

path:array[1..100,1..100] of longint;

dist,last:array[1..100] of longint;//last[i]记录节点i是由哪一个点更新而来的。

e:array[1..100] of inf;

flag:array[1..100] of boolean;

n,sum,top:longint;


procedure linit;//初始化

var

  vi,vj,w:longint;

begin

  read(n);

  for vi:=1 to n do

   for vj:=1 to n do

    read(path[vi,vj]);

end;


procedure prim(vi:longint);//Prim算法

var

  vj,vk,min,p:longint;

begin

  for vj:=1 to n do

  begin

   dist[vj]:=path[vi,vj];

   last[vj]:=vi;

  end;

  flag[vi]:=true;

  for vj:=1 to n-1 do

  begin

   min:=maxlongint;

   for vk:=1 to n do

    if (dist[vk]<min) and (not flag[vk]) then

    begin

     p:=vk;

     min:=dist[vk];

    end;

   flag[p]:=true;

   if dist[p]<>0 then

   begin

    inc(sum,min);//更新费用

    inc(top);//统计边数

    if last[p]<p then

    begin

     e[top].x:=last[p];//用last[p]与p确定一条线段

     e[top].y:=p;

    end

     else

    begin

     e[top].x:=p;

     e[top].y:=last[p];

    end;

   end;

   for vk:=1 to n do

    if dist[vk]>path[p,vk] then

    begin

     dist[vk]:=path[p,vk];

     last[vk]:=p;//更新last

    end;

  end;

end;


procedure print;//输出

var

  vi:longint;

begin

  writeln(top);//输出边数

  for vi:=1 to top do

   writeln(e[vi].x,' ',e[vi].y);//输出边

  writeln(sum);//输出总费用

end;


begin

linit;//初始化

prim(1);//最小生成树

print;

end.


多年未打prim,复习一下就好。

评论
©主题 —— Powered by LOFTER