Island Transport HDU - 4280 最大流 ISAP

本文介绍了解决大规模网络最大流问题的一种高效算法-ISAP。该算法通过改进搜索策略,能够在较短时间内找到从源点到汇点的最大流量路径。特别适用于边数和点数都非常大的情况,例如本例中讨论的含有20组数据、每组数据包含高达10万节点与边的问题实例。

题目链接: Island Transport HDU - 4280

题目大意

n个顶点, m条边( 2n,m105 ), 每条边有容量限制, 求起点到终点的最大流量, 有最多20组数据
数据规模比较大, Dinic会超时, 要用sap

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <string>
#include <map>

using namespace std;


/*ISAP+bfs初始化+栈优化
*/
const int maxn=100010;//点数的最大值
const int maxm=200010;//边数的最大值
const int inf=0x3f3f3f3f;
struct Edge {
  int to,next,cap,flow;
}edge[maxm];//注意是maxm
int tol;
int head[maxn];
int cur[maxn],d[maxn];// 当前弧下标   结点到汇点距离下界
int p[maxn],gap[maxn];//可增广路上的上一条弧   gap优化  //比dinic多的两个数组
void init(){
  tol=0;
  memset(head, -1, sizeof(head));
}

void addedge(int u,int v,int w,int rw = 0){
  edge[tol].to=v; edge[tol].cap=w; edge[tol].flow=0;
  edge[tol].next=head[u]; head[u]=tol++;
  edge[tol].to=u; edge[tol].cap=rw; edge[tol].flow=0;
  edge[tol].next=head[v]; head[v]=tol++;
}

int Q[maxn];
void bfs(int s,int t){//逆向进行bfs
  memset(d, -1, sizeof(d));
  memset(gap, 0, sizeof(gap));
  gap[0]=1;
  int front=0, rear=0;
  d[t]=0;
  Q[rear++]=t;
  while(front!=rear){
  int u=Q[front++];
    for(int i=head[u]; i!=-1; i=edge[i].next){
      int v=edge[i].to;
      if(d[v]!=-1)continue;
      Q[rear++]=v;
      d[v]=d[u]+1;
      gap[d[v]]++;
    }
  }
}

int S[maxn];
int sap(int s,int t,int N){
  bfs(s, t);
  memcpy(cur, head, sizeof(head));
  int top=0;
  int u=s;
  int ans=0;
  while(d[s]<N){
    if(u==t){
      int Min=inf;
      int inser;
      for(int i=0; i<top; i++)//找最小残量值
        if(Min>edge[S[i]].cap-edge[S[i]].flow){
          Min=edge[S[i]].cap-edge[S[i]].flow;
          inser=i;
        }
      for(int i=0; i<top; i++){//增广
        edge[S[i]].flow+=Min;
        edge[S[i]^1].flow-=Min;
      }
      ans+=Min;
      top=inser;
      u=edge[S[top]^1].to;
      continue;
    }
    bool ok=false;
    int v;
    for(int i=cur[u]; i!=-1; i=edge[i].next){
      v=edge[i].to;
      if(edge[i].cap-edge[i].flow && d[v]+1==d[u]){////Advance前进
        ok=true;
        cur[u]=i;
        break;
      }
    }
    if(ok){
      S[top++]=cur[u];
      u=v;
      continue;
    }
    //Retreat走不动了,撤退
    int Min=N;
    for(int i=head[u]; i!=-1; i=edge[i].next)
      if(edge[i].cap-edge[i].flow && d[edge[i].to]<Min){
        Min=d[edge[i].to];
        cur[u]=i;
      }
    gap[d[u]]--;
    if(!gap[d[u]])return ans;
    d[u]=Min+1;
    gap[d[u]]++;
    if(u!=s)u=edge[S[--top]^1].to;//退一步,沿父边返回
  }
  return ans;
}

int main()
{
    int tt;
    cin >> tt;
    while(tt--)
    {
        int n, m, x, y;
        init();
        scanf("%d%d", &n, &m);
        int S, T, mi = inf, ma = -inf;

        for(int i=0; i<n; ++i)
        {
            scanf("%d%d", &x, &y);
            if(x < mi)
            {
                mi = x;
                S = i;
            }
            if(x > ma)
            {
                ma = x;
                T = i;
            }
        }

        int c;
        for(int i=0; i<m; ++i)
        {
            scanf("%d%d%d", &x, &y, &c);
            --x, --y;
            addedge(x, y, c, c);
        }

        printf("%d\n", sap(S, T, n));
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值