交通查询系统

Description

  众所周知,交通情况是大家在日常生活中比较关心的问题。一条道路所允许的最大同时平行车辆数称为这条道路的最大吞吐量,我们假定这里都是双向道路。而我们经常要想知道两个站之间的最大总吞吐量。
  由于你的才华横溢,过于出众,于是你就被交通部任命设计这个交通部的查询软件,允许市民查询目前城市的任意两个站之间的最大总吞吐量。

Input

  输输入的第一行包括两个整数N和M,分别表示该城市的站点个数和道路的个数。
  接下去有M行,每行有三个整数u、v、c(1<=u、v<=N,1<=c<=10^4),表示u和v站点之间有一条道路,且吞吐量为c。
  然后一行有一个整数Q。代表市民的查询次数。
  接下去有Q行,每行有两个整数s、t(1<=s、t<=N),表示市民的一个查询。
  50%的数据保证N<=50,Q<=10000
  100%的数据保证N<=300 和Q<=100000

Output

  对于每组查询(s、t),输出s到t的最大总吞吐量。

Input

  2 1


  1 2 2

  2

  1 2

  2 1

Output

  2
 
 2

  在读入图的时候,先把任意两个点之间的最大流求出来,用dist[i,j]保存,然后在查询的时候,只需要直接输出就行了。。。  
  一个最小割,要注意fillchar的使用,赋最大值的时候用fillchar(f,sizeof(f),127)或fillchar(f,sizeof(f),$7f),就是赋成maxlongint;赋成-1是fillchar(f,sizeof(f),255);(正确性有待考证),不过最好再加个 div 2,免得256.。。。。 
    另外,这道题还有一个坑爹的地方是,两个点之间不只一条边。。。其实noi的题大多都有这样的陷阱,所以,除非题目特别说明,还是当做不只一条边来做。。。。。
    
var n,m,ans,q,flow,s,t,maxn:longint;
    f,dist,g:array[0..500,0..500]of longint;
    dis,now,fa,fan,pre,sum:array[0..500]of longint;
    v:array[0..500]of boolean;
procedure init;
  var i,j,x,y,c:longint;
    begin
      fillchar(g,sizeof(g),0);
      readln(n,m);
      for i:=1 to m do
        begin
          readln(x,y,c);
          if c>f[x,y] then
            begin
              g[x,y]:=g[x,y]+c;
              g[y,x]:=g[y,x]+c;
            end;
        end;
      maxn:=maxlongint div 4; 
    end;
procedure sap;
  var i,j,k,flow,minn:longint;vis:boolean;
    begin
      ans:=0;
      fillchar(sum,sizeof(sum),0);
      fillchar(dis,sizeof(dis),0);
      for i:=1 to n do now[i]:=1;
      sum[0]:=n;
      i:=s;flow:=maxn;
      while dis[s]<n do
        begin
          fan[i]:=flow;
          vis:=false;
          for j:=now[i] to n do
            if (f[i,j]>0)and(dis[i]=dis[j]+1) then
              begin
                now[i]:=j;
                vis:=true;
                if f[i,j]<flow then flow:=f[i,j];
                pre[j]:=i;
                i:=j;
                if i=t then
                  begin
                    ans:=ans+flow;
                    while i<>s do
                      begin
                        k:=pre[i];
                        f[k,i]:=f[k,i]-flow;
                        f[i,k]:=f[i,k]+flow;
                        i:=k;
                      end;
                    flow:=maxn
                  end;
                break;
              end;
            if vis then continue;
            minn:=maxn;
            for j:=1 to n do
              if (f[i,j]>0)and(dis[j]<minn) then
                begin
                  now[i]:=j;minn:=dis[j];
                end;
            dec(sum[dis[i]]);
            if sum[dis[i]]=0 then exit;
            dis[i]:=minn+1;
            inc(sum[dis[i]]);
            if i<>s then
              begin
                i:=pre[i];flow:=fan[i];
              end;
         end;
    end;
function min(a,b:longint):longint;
  begin
    if a>b then exit(b) else exit(a);
  end;
procedure dfs(i:longint);
  var j:longint;
    begin
      v[i]:=true;
      for j:=1 to n do
        if (f[i,j]>0)and(not v[j]) then dfs(j);
    end;
procedure ask;
  var i,x,y:longint;
    begin
      readln(q);
      for i:=1 to q do
        begin
          readln(x,y);
          if x=y then writeln(0) 
            else 
              writeln(dist[x,y]);
        end;
    end;
procedure main;
  var i,j:longint;
    begin
      fillchar(dist,sizeof(dist),127 div 2);
      for i:=1 to n do fa[i]:=1;
      for i:=2 to n do
        begin
          f:=g;
          s:=fa[i];t:=i;
          sap;
          fillchar(v,sizeof(v),0);
          dfs(s);
          for j:=i+1 to n do
            if not v[j] then fa[j]:=i;
          for j:=1 to i-1 do
            begin
              dist[j,i]:=min(dist[j,fa[i]],ans);
              dist[i,j]:=dist[j,i];
            end;
         end;
      ask;
    end;
begin
 assign(input,'traffic.in');reset(input);
 assign(output,'traffic.out');rewrite(output);
  init;
  main;
 close(input);close(output);
end.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值