【Kruskal】公路建设(Road.exe, 1s, 64M)

 

公路建设(Road.exe, 1s, 64M)

【问题描述】

A国是一个新兴的国家,有N个城市,分别编号为1,2.3…N。政府想大搞公路建设,提供了优惠政策:对于每一个投资方案的预计总费用,政府负担50%,并且允许投资的公司对过往的汽车收取连续5年的养路费。世界各地的大公司纷纷投资,并提出了自己的建设方案,他们的投资方案包括这些内容:公路连接的两座城市的编号,预计的总费用(假设他们的预计总师准确的)。你作为A国公路规划局的总工程师,有权利决定每一个方案是否接受。但是政府给你的要求是:

1)要保证各个城市之间都有公路直接或间接相连。

2)因为是新兴国家,政府的经济实力还不强。政府希望负担最少的费用。

    因为大公司并不是同时提出方案,政府希望每接到一个方案,就可以知道当前需要负担的最小费用和接受的投资方案,以便随时开工。关于你给投资公司的回复可以等到开工以后再给。

注意:A国一开始是没有公路的。

【数据说明】A国的城市数目N<=500,投资的方案总数M<=2000。

【输入】输入文件名:Road.in

第1行有两个数字:N、M

第2行到第M+1行给出了各个投资方案,第i行的方案编号为i-1

编号小的方案先接到,一个方案占一行,每行有3个数字,分别是连接的两个城市编号a、b,和投资的预计总费用cost。

【输出】输出文件名:Road.out

输出文件共有M行。

每一行的第一个数字是当前政府需要负担的最少费用(保留1位小数),后面是X个数字,表示当前政府接受的方案的编号,不要求从小到大排列。但如果此时接受的所有投资方案不能保证政府的第一条要求,那么这一行只有一个数字0

【样例】

Road.in

Road.out

3 5

1 2 4

1 3 4

2 3 4

1 3 2

1 2 2

0

4.0 1 2

4.0 1 2

3.0 1 4

2.0 4 5

================================

kruskal

===========================

type
  node=record
         x,y,v,o:longint;
       end;
var
  n,m:longint;
  fa:array[1..250000]of node;
  f_fa:array[1..250000]of longint;
  fa_s:longint;
  map:array[1..500,1..500]of longint;
  odd:array[1..500,1..500]of longint;
  ans_odd:array[1..250000]of longint;
  f_bo:array[1..500]of boolean;
procedure init;
begin
  assign(input,'road.in');
  assign(output,'road.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

function find(x:longint):longint;
begin
  if f_fa[x]=x then exit(x)
               else begin f_fa[x]:=find(f_fa[x]); exit(f_fa[x]); end;
end;

procedure merge(a,b:longint);
var
  x,y:longint;
begin
  x:=find(a);
  y:=find(b);
  f_fa[x]:=y;
end;

procedure qsort(s,t:longint);
var
  i,j:longint;
  x:longint;
  tem:node;
begin
  x:=fa[(s+t)shr 1].v;
  i:=s; j:=t;
  repeat
    while x<fa[j].v do dec(j);
    while fa[i].v<x do inc(i);
    if i<=j then
      begin
        tem:=fa[i];
        fa[i]:=fa[j];
        fa[j]:=tem;
        inc(i); dec(j);
      end;
  until i>j;
  if i<t then qsort(i,t);
  if s<j then qsort(s,j);
end;

procedure main;
var
  i,j,k:longint;
  x,y,z:longint;
  t:longint;
  fa_t,ans:longint;
begin
  readln(n,m);
  fillchar(f_bo,sizeof(f_bo),true);
  fillchar(map,sizeof(map),$7);
  t:=0;
  for i:=1 to m do
    begin
      readln(x,y,z);
      if map[x,y]>z then
        begin
          map[x,y]:=z;
          odd[x,y]:=i;
          odd[y,x]:=i;
          if f_bo[x] then
            begin
              f_bo[x]:=false;
              inc(t);
            end;
          map[y,x]:=z;
          if f_bo[y] then
            begin
              f_bo[y]:=false;
              inc(t);
            end;
        end;
      if t<n then writeln(0)
       else
        if t=n then
          begin
            fa_s:=0;
            for j:=1 to n do
              for k:=j+1 to n do
                if map[j,k]<100000 then
                begin
                  inc(fa_s);
                  fa[fa_s].x:=j;
                  fa[fa_s].y:=k;
                  fa[fa_s].v:=map[j,k];
                  fa[fa_s].o:=odd[j,k];
                end;
            qsort(1,fa_s);
            for j:=1 to n do f_fa[j]:=j;
            
            fa_t:=0; ans:=0;
            for j:=1 to fa_s do
              begin
                if fa_t=n-1 then break;
                if find(fa[j].x)<>find(fa[j].y) then
                  begin
                    inc(fa_t);
                    ans_odd[fa_t]:=fa[j].o;
                    ans:=ans+fa[j].v;
                    merge(fa[j].x,fa[j].y);
                  end;
              end;
            write(ans/2:0:1,' ');
            for j:=1 to fa_t do write(ans_odd[j],' ');
            writeln;
          end;
    end;
end;

begin
  init;
  main;
  terminate;
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值