IOI-2003-Maintain

[描述]:
在一个初始化为空的无向图中,不断加入新边。如果当前图连通,就求出当前图最小生成树的总权值;否则,输出-1

[分析]:
通过并查集判断连通性,若当前边的两端点已连通,则在这条环上找最大的一条边删去。
[代码]:

program maintain;
var
   father:array[1..200] of longint;
   g:array[1..200,1..200] of longint;
   N,M,Len_count,Cost,i,S,T,L:longint;
   
   q:array[0..200] of longint; top,last:longint;
   pre:array[1..200] of longint;
   v:array[1..200] of boolean;

function f(x:longint):longint;
begin
     if father[x]=0 then exit(x)
     else begin
          father[x]:=f(father[x]);
          exit(father[x]);
     end;
end;

procedure Sift(S,T,L:longint);
var
   Max,SS,TT,i,j:longint;
begin
     fillchar(v,sizeof(v),false);
     top:=0; last:=1; q[1]:=S; v[s]:=true;
     while (top<last)and(not v[T]) do begin
           inc(top);
           i:=q[top];
           for j:=1 to N do
               if (not v[j])and(g[i,j]>0) then begin
                  v[j]:=true;
                  pre[j]:=i;
                  inc(last);
                  q[last]:=j;
               end;
     end;

     i:=T; Max:=0;
     while i<>S do begin
           if g[pre[i],i]>Max then begin
              Max:=g[pre[i],i];
              SS:=pre[i];
              TT:=i;
           end;
           i:=pre[i];
     end;
     if Max>L then begin
        g[SS,TT]:=0;
        g[TT,SS]:=0;
        g[S,T]:=L;
        g[T,S]:=L;
        dec(Cost,Max);
        inc(Cost,L);
     end;
     
end;

begin
     assign(input,'maintain.in');
     assign(output,'maintain.out');
     reset(input);
     rewrite(output);

     fillchar(father,sizeof(father),0);
     fillchar(g,sizeof(g),0);
     Len_count:=0;
     Cost:=0;

     readln(N,M);
     for i:=1 to M do begin
         readln(S,T,L);

         if f(S)<>f(T) then begin
            father[f(S)]:=f(T);
            g[S,T]:=L;
            g[T,S]:=L;
            inc(Len_count);
            inc(Cost,L);
         end else Sift(S,T,L);
         
         if Len_count=N-1 then
            writeln(Cost)
         else writeln(-1);
         
         {
         Writeln(#32#32#32,'Debug:');
         Writeln(#32#32#32,'LenCount:',Len_count);
         for j:=1 to N-1 do
         for k:=j+1 to N do
             if g[j,k]<>0 then
                Writeln(#32#32#32,'g[',j,',',k,']:=',g[j,k]);
         }
     end;
     
     close(input);
     close(output);
end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值