APIO09-Atm

这题本身没什么技术性,但是这个数据太强了。。。
说下我的思路:
step1.求强连通分量,缩点,消圈,用O(N+M)的Tarjan算法显然是最佳选择,但是要注意到:如果用递归Tarjan会爆栈的,所以要手动写个栈(想想就胃疼)。
step2.求最大权值路径:
法一.spfa之,复杂度O(KE),但是实践证明这数据居然把spfa常数卡住了(或许是我缩点过程耗时大了,反正超了一个点)。
法二.拓扑排序+图上DP,复杂度O(N+M),满分。
==================================================================
贴代码(7kb):

program APIO09AIM;
const MaxN=500000;
type link=^node; node=record x:longint; back,next:link; end;//back为反向边指针
var Gz,Gf:array[1..MaxN] of link;//图分了双向边存储,便于combine操作实现
    Low,Dfn,Weight,Dist,Stack,Du,Ar:array[1..MaxN] of longint;
    isVisit,inStack,isEnd:array[1..MaxN] of boolean;
    TarStack:Array[1..MaxN] of record i:longint; p:link; end;
    N,S,Ans,Top,Index,TarTop:longint;

//Simple
procedure Swap(var i,j:longint);
var tmp:longint;
begin tmp:=i; i:=j; j:=tmp;
end;
function Min(a,b:longint):longint;
begin if a<b then exit(a) else exit(b);
end;
function Max(a,b:longint):longint;
begin if a>b then exit(a) else exit(b);
end;
//End of Simple

//Stack
procedure Push(i:longint);
begin inc(Top); Stack[Top]:=i;
      inStack[i]:=True;
end;
function Pop:longint;
begin pop:=Stack[Top]; dec(Top);
      inStack[Pop]:=false;
end;
//End of Stack

//Graph
procedure Conn(i,j:longint);//(i->j);
var pz,pf:link;
begin
     new(pz); new(pf);
     with pz^ do begin x:=j; next:=Gz[i]; back:=pf; end; Gz[i]:=pz;
     with pf^ do begin x:=i; next:=Gf[j]; back:=pz; end; Gf[j]:=pf;
end;
procedure Combine(i,j:longint);//合并节点操作,注意可能存在边<i,i>
var p:link;
begin if j=S then Swap(i,j);
      //writeln('Combine(',i,',',j,');');
      while Gz[j]<>nil do begin
           p:=Gz[j]; Gz[j]:=Gz[j]^.next;
           p^.back^.x:=i;
           p^.next:=Gz[i]; Gz[i]:=p;
      end;
      while Gf[j]<>nil do begin
           p:=Gf[j]; Gf[j]:=Gf[j]^.next;
           p^.back^.x:=i;
           p^.next:=Gf[i]; Gf[i]:=p;
      end;
      inc(Weight[i],Weight[j]);
      isEnd[i]:=isEnd[i] or isEnd[j];
end;
//End of Graph

//Init
procedure Init;
var M,P,i,a,b:longint;
begin
     readln(N,M);
     for i:=1 to M do begin
         readln(a,b);
         Conn(a,b)
     end;
     for i:=1 to N do readln(Weight[i]);
     readln(S,P);
     fillchar(isEnd,sizeof(isEnd),false);
     for i:=1 to P do begin
         read(a);
         isEnd[a]:=true;
     end;
end;
//End of Init;

//ConTract(DG)//递归版本的Tarjan算法
procedure Tarjan_DG(i:longint);
var p:link; j:longint;
begin isVisit[i]:=True;
      inc(Index); Low[i]:=Index; Dfn[i]:=Index;
      Push(i);
      p:=Gz[i];
      while p<>nil do begin
           if not isVisit[p^.x] then begin
              Tarjan_DG(p^.x);
              Low[i]:=Min(Low[i],Low[p^.x]);
           end else if inStack[p^.x] then
               Low[i]:=Min(Low[i],Low[p^.x]);
           p:=p^.next;
      end;
      if Low[i]=Dfn[i] then
        repeat
              j:=Pop;
              if i<>j then Combine(i,j);
        until j=i;
end;
procedure ConTract_DG;//消圈,与递归版本的Tarjan配合
begin
     Index:=0; Top:=0;
     fillchar(isVisit,sizeof(isVisit),false);
     fillchar(inStack,sizeof(inStack),false);
     Tarjan_DG(S);
end;
//End of ConTract(DG)

//Contract(UDG)//手动栈的Tarjan
procedure ConTract_UDG;
var i,j,res:longint;
    p:Link;
begin
     Fillchar(isVisit,sizeof(isVisit),false); isVisit[S]:=True;
     fillchar(inStack,sizeof(inStack),false); Top:=0; Push(S);
     TarTop:=1; TarStack[1].i:=S;
     TarStack[1].p:=Gz[S];
     Low[S]:=1; Dfn[S]:=1; Index:=1; res:=-1;
     while TarTop>0 do begin
           i:=TarStack[TarTop].i;
           p:=TarStack[TarTop].p;
           if p=nil then begin
              if Low[i]=Dfn[i] then
                 repeat
                       j:=Pop;
                       if j<>i then Combine(i,j);
                 until j=i;
                 dec(TarTop);
                 res:=1;
           end else if not isVisit[p^.x] then begin
                  inc(TarTop);
                  TarStack[TarTop].i:=p^.x;
                  isVisit[p^.x]:=True;
                  inc(Index);
                  Low[TarStack[TarTop].i]:=Index;
                  Dfn[TarStack[TarTop].i]:=Index;
                  Push(p^.x);
                  TarStack[TarTop].p:=Gz[p^.x];
                  res:=-1;
           end else begin
                    if res=1 then Low[i]:=Min(Low[i],Low[p^.x])
                    else if inStack[p^.x] then Low[i]:=Min(Low[i],Low[p^.x]);
                    TarStack[TarTop].p:=TarStack[TarTop].p^.next;
                    res:=-1;
           end;
     end;
end;

//End of ConTract(UDG)

//Spfa(tle)//spfa法求最大权值路径,Tle了一个点
procedure spfa;//S->>
var p:link; x:longint;
begin
     Ans:=0;
     fillchar(Dist,Sizeof(Dist),0);
     fillchar(inStack,sizeof(inStack),false);
     Top:=0; push(S);
     Dist[S]:=Weight[S];
     while Top>0 do begin
           x:=Pop;
           if isEnd[x] then Ans:=Max(Ans,Dist[x]);
           p:=Gz[x];
           while p<>nil do begin
                 if p^.x<>x then
                 if Dist[x]+Weight[p^.x]>Dist[p^.x] then begin
                    Dist[p^.x]:=Dist[x]+Weight[p^.x];
                    if not inStack[p^.x] then Push(p^.x);
                 end;
                 p:=p^.next;
           end;
     end;
end;
//End Spfa

//TpSort;//拓扑排序
procedure TpSort;
var i,Count:longint; p:link;
begin
     Top:=0;
     for i:=1 to N do begin
         Du[i]:=0;
         p:=Gz[i]; while p<>nil do begin
                   if p^.x<>i then inc(Du[i]);
                   p:=p^.next;
         end;
         if Du[i]=0 then Push(i);
     end;
     Count:=0;
     while Top>0 do begin
           i:=Pop;
           p:=Gf[i]; while p<>nil do begin
                     if p^.x<>i then begin
                        dec(Du[p^.x]);
                        if Du[p^.x]=0 then Push(p^.x);
                     end;
                     p:=p^.next;
           end;
           inc(Count); Ar[Count]:=i; //writeln('TpSort(',i,');');
     end;
end;
//

//Dp//拓扑排序后图上DP
procedure Dp;
var i,x:longint; p:link;
begin
     Ans:=0;
     for i:=N downto 1 do begin
         x:=Ar[i];
         Dist[x]:=Weight[x];
         p:=Gf[x]; while p<>nil do begin
                   if p^.x<>x then Dist[x]:=Max(Dist[x],Weight[x]+Dist[p^.x]);
                   p:=p^.next;
         end;
         if isEnd[x] then Ans:=Max(Ans,Dist[x]);
     end;
end;
//End of Ep

//Main//主函数
procedure Main;
begin
     Init;
     ConTract_UDG;
     TpSort;Dp;{spfa is tle}
     write(Ans);
end;
//End of Main

//Print;//Debug部分,请忽略
procedure print;
var i:longint; p:link;
begin for i:=1 to N do begin
          p:=Gz[i]; while p<>nil do begin
                    writeln(i,'>>',p^.x);
                    p:=p^.next;
          end;
      end;
      for i:=1 to N do writeln('Weight[',i,']=',weight[i]);
end;
//End of print

begin
     Assign(input,'atm.in'); reset(input);
     Assign(output,'atm.out'); rewrite(output);
     Main;               //Print;
     close(input); close(output);
end.
==================================================================
这题真的不难,只不过手动开栈很闹心啊!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值