网络流&&费用流模板(OrzLcomyn神犇的模板)

神犇链接在我友链里.
这篇文章转来用用,后面自己再整合一套.
ISAP
1、有源有汇有上界无下界最大流 code1(邻接矩阵版):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int map[201][201],n;
int lev[201],pre[201],gap[201],cur[201]; 
int ISAP(int vs,int vt)
{
    memset(gap,0,sizeof(gap));
    memset(pre,-1,sizeof(pre));
    memset(lev,0,sizeof(lev));
    int i,v,u=pre[vs]=vs,aug,maxt=0,minl;
    gap[0]=vt;
    for (i=vs;i<=vt;++i)
      cur[i]=1;
    while (lev[vs]<vt)
      {
        for (v=cur[u];v<=vt;v++)
          if (lev[u]==lev[v]+1&&map[u][v]>0)
            {cur[u]=v; break;}
        if (v<=vt)
          {
            pre[v]=u;
            u=v;
            if (v==vt)
              {
                aug=2100000000;
                for (i=v;i!=vs;i=pre[i])
                  if (map[pre[i]][i]<aug)
                    aug=map[pre[i]][i];
                maxt+=aug;
                for (i=v;i!=vs;i=pre[i])
                  {
                    map[pre[i]][i]-=aug;
                    map[i][pre[i]]+=aug;
                  }
                u=vs;
              }
          }
        else
          {
            minl=vt;
            for (v=1;v<=vt;++v)
              if (map[u][v]>0&&lev[v]<minl)
                minl=lev[v];
            gap[lev[u]]--;
            if (gap[lev[u]]==0) break;
            lev[u]=minl+1;
            cur[u]=1;
            gap[lev[u]]++;
            u=pre[u];
          }
      }
    return maxt;
}
int main()
{
    int i,j;
    scanf("%d",&n);
    for (i=1;i<=n;++i)
      for (j=1;j<=n;++j)
        scanf("%d",&map[i][j]);
    printf("%d\n",ISAP(1,n));
}

code2(next数组版):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdio>
using namespace std;
struct hp{
    int u,v,c;
}a[60000];
int map[2000][2000];
int point[2000],next[30000];
int pre[30000],gap[2000],lev[2000],cur[2000];
int ISAP(int vs,int vt)
{
    memset(lev,0,sizeof(lev));
    memset(gap,0,sizeof(gap));
    memset(pre,0,sizeof(pre));
    int i,v,u=vs,maxt=0,minl,aug,c;
    bool f=false;
    gap[0]=vt-vs+1;
    while (lev[vs]<vt)
      {
        f=false;
        for (v=cur[u];v!=0;v=next[v])
          if (lev[u]==lev[a[v].v]+1&&a[v].c>0)
            {f=true; cur[u]=v; break;}
        if (f)
          {
            pre[a[v].v]=v;
            u=a[v].v;
            if (u==vt)
              {
                aug=2100000000;
                for (i=v;i!=0;i=pre[a[i].u])
                  if (a[i].c<aug)
                    aug=a[i].c;
                maxt+=aug;
                for (i=v;i!=0;i=pre[a[i].u])
                  {
                    a[i].c-=aug;
                    a[i^1].c+=aug;
                  }
                u=vs;
              }
          }
        else
          {
            minl=vt;
            for (i=point[u];i!=0;i=next[i])
              if (minl>lev[a[i].v]&&a[i].c>0)
                minl=lev[a[i].v];
            gap[lev[u]]--;
            if (gap[lev[u]]==0) break;
            lev[u]=minl+1;
            cur[u]=point[u];
            gap[lev[u]]++;
            if (u!=vs) u=a[pre[u]].u; 
          }
      }
    return maxt;
}
int main()
{
    int i,n,j,c,e=1;
    scanf("%d",&n);
    for (i=1;i<=n;++i)
      for (j=1;j<=n;++j)
        {
          scanf("%d",&c);
          if (c!=0)
            {
              e++;
              a[e].u=i; a[e].v=j; a[e].c=c;
              next[e]=point[i];
              cur[i]=point[i]=e;
              e++;
              a[e].u=j; a[e].v=i; a[e].c=0;
              next[e]=point[j];
              cur[j]=point[j]=e;
            }
        }
    printf("%d\n",ISAP(1,n));
}

2、(1)多源多汇有上界无下界最大流 ,设置一个超级源点,流向所有入度为0的原源点,容量为无穷,再设置一个超级汇点,使所有出度为0的原汇点,容量为无穷。求一遍最大流即可。
(2)有源有汇有点界的最大流,对每个点插成两个点,求一遍最大流即可。
3、无源无汇有上界有下界最大流:构图时,依然设置超级源点和超级汇点,但如果该节点的下界是净流出(下界的出度减入度>0)的话,该点到超级汇点的权等于净流出量;如果该节点的下界是净流入的话(该点的出度减入度<0)的话,超级源点到该点的权等于净流入量。求一遍最大流,如果超级源点的出度满流的话,即存在最大流,输出即可。否则则不存在最大流 code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int map[150][150],n;
int lev[150],pre[150],gap[150];
int ISAP(int vs,int vt)
{
    memset(lev,0,sizeof(lev));
    memset(gap,0,sizeof(gap));
    memset(pre,-1,sizeof(pre));
    int i,v,u=pre[vs]=vs,minl,aug,maxt=0;
    gap[0]=vt-vs+1;
    while (lev[vs]<vt)
      {
        for (v=vs;v<=vt;v++)
          if (map[u][v]>0&&lev[u]==lev[v]+1)
            break;
        if (v<=vt)
          {
            pre[v]=u;
            u=v;
            if (v==vt)
              {
                aug=2100000000;
                for (i=v;i!=vs;i=pre[i])
                  if (map[pre[i]][i]<aug)
                    aug=map[pre[i]][i];
                maxt+=aug;
                for (i=v;i!=vs;i=pre[i])
                  {
                    map[pre[i]][i]-=aug;
                    map[i][pre[i]]+=aug;
                  }
                u=vs;
              }
          }
        else
          {
            minl=vt;
            for (v=vs;v<=vt;++v)
              if (map[u][v]>0&&lev[v]<minl)
                minl=lev[v];
            gap[lev[u]]--;
            if (gap[lev[u]]==0) break;
            lev[u]=minl+1;
            gap[lev[u]]++;
            u=pre[u];
          }
      }
    return maxt;
}
int main()
{
    int i,j,m,inf,outf,sum,ans,p=0;
    int pic[150][150][2];
    scanf("%d",&n);
    for (i=1;i<=n;++i)
      for (j=1;j<=2*n;++j)
        scanf("%d",&pic[i][(j+1)/2][1-j%2]);
    for (i=1;i<=n;++i)
      {
        inf=0; outf=0;
        for (j=1;j<=n;++j)
          {
            inf+=pic[j][i][0];
            outf+=pic[i][j][0];
            map[i][j]=pic[i][j][1]-pic[i][j][0];
          }
        sum=outf-inf;
        if (sum<0)
          {
            map[0][i]=abs(sum);
            p+=abs(sum);
          }
        else
          map[i][n+1]=abs(sum);
      }
    ans=ISAP(0,n+1);
    if (ans==p)
      printf("%d\n",ans);
    else
      printf("0\n"); 
}

4、有源有汇有上界有下界最大流,使汇点到源点有一条上界为无穷,下界为0的边(注意,此边在构图之后加),使它变为无源无汇图,构图和判断同无源无汇有上界有下界最大流,但输出时,先删去汇点到源点的无穷边,再跑一遍原源点到原汇点的最大流,输出即可 code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int map[150][150],n;
int lev[150],pre[150],gap[150];
int ISAP(int vs,int vt)
{
    memset(lev,0,sizeof(lev));
    memset(gap,0,sizeof(gap));
    memset(pre,-1,sizeof(pre));
    int i,v,u=pre[vs]=vs,minl,aug,maxt=0;
    gap[0]=vt-vs+1;
    while (lev[vs]<vt)
      {
        for (v=vs;v<=vt;v++)
          if (map[u][v]>0&&lev[u]==lev[v]+1)
            break;
        if (v<=vt)
          {
            pre[v]=u;
            u=v;
            if (v==vt)
              {
                aug=2100000000;
                for (i=v;i!=vs;i=pre[i])
                  if (map[pre[i]][i]<aug)
                    aug=map[pre[i]][i];
                maxt+=aug;
                for (i=v;i!=vs;i=pre[i])
                  {
                    map[pre[i]][i]-=aug;
                    map[i][pre[i]]+=aug;
                  }
                u=vs;
              }
          }
        else
          {
            minl=vt;
            for (v=vs;v<=vt;++v)
              if (map[u][v]>0&&lev[v]<minl)
                minl=lev[v];
            gap[lev[u]]--;
            if (gap[lev[u]]==0) break;
            lev[u]=minl+1;
            gap[lev[u]]++;
            u=pre[u];
          }
      }
    return maxt;
}
int main()
{
    int i,j,m,inf,outf,sum,ans,p=0;
    int pic[150][150][2];
    scanf("%d",&n);
    for (i=1;i<=n;++i)
      for (j=1;j<=2*n;++j)
        scanf("%d",&pic[i][(j+1)/2][1-j%2]);
    for (i=1;i<=n;++i)
      {
        inf=0; outf=0;
        for (j=1;j<=n;++j)
          {
            inf+=pic[j][i][0];
            outf+=pic[i][j][0];
            map[i][j]=pic[i][j][1]-pic[i][j][0];
          }
        sum=outf-inf;
        if (sum<0)
          {
            map[0][i]=abs(sum);
            p+=abs(sum);
          }
        else
          map[i][n+1]=abs(sum);
      }
    map[n][1]=2100000000;
    ans=ISAP(0,n+1);
    if (ans==p)
      {
        map[n][1]=0;
        ans=ISAP(1,n);
        printf("%d\n",ans);
      }
    else
      printf("0\n"); 
}

5、费用流模板,先跑一遍最短路,再在最短路上进行增广, ans+=dis(vs,vt)maxflow() ,直到无法求出最短路。输出ans即可。code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int point[101],next[5000],queue[500],dis[101],minn[101],pre[101],e,head,tail,ans=0,n,st,en;
bool exist[101];
struct hp{
    int u,v,c,w;
}a[5000];
void add(int u,int v,int c,int w)
{
    e++;
    a[e].u=u; a[e].v=v; a[e].c=c; a[e].w=w; next[e]=point[u]; point[u]=e;
    e++;
    a[e].u=v; a[e].v=u; a[e].c=0; a[e].w=0-w; next[e]=point[v]; point[v]=e;
}
bool work(int vs,int vt)
{
    memset(exist,false,sizeof(exist));
    memset(dis,127,sizeof(dis));
    memset(pre,0,sizeof(pre));
    int i,j,u,stan=dis[1]; minn[vs]=dis[1];
    exist[vs]=true; dis[vs]=0; head=0; tail=1; queue[tail]=vs;
    while (head!=tail)
      {
        head=head%500+1;
        u=queue[head];
        exist[u]=false;
        for (i=point[u];i!=0;i=next[i])
          {
            if (a[i].c>0&&dis[a[i].v]>dis[u]+a[i].w)
              {
                dis[a[i].v]=dis[u]+a[i].w;
                pre[a[i].v]=i;
                minn[a[i].v]=min(minn[u],a[i].c);
                if (!exist[a[i].v])
                  {
                    tail=tail%500+1;
                    queue[tail]=a[i].v;
                    exist[a[i].v]=true;
                  }
              }
          }  
      }
    if (dis[vt]==stan) return false;
    ans+=dis[vt]*minn[vt];
    for (i=pre[vt];i!=0;i=pre[a[i].u])
      {
        a[i].c-=minn[vt];
        a[i^1].c+=minn[vt];
      }
    return true;
}
int main()
{
    int i,j,c,w;
    scanf("%d%d%d",&n,&st,&en);
    e=1;
    for (i=1;i<=n;++i)
      for (j=1;j<=n;++j)
        {
          scanf("%d%d",&c,&w);
          if (c) add(i,j,c,w);
        }  
    while (work(st,en));
    printf("%d\n",ans);
}

最大权闭合子图code:

#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 2100000000
using namespace std;
struct hp{
    int u,v,c;
}a[500000];
int e,n,m;
int p[5001];
int point[56000],next[500000],pre[56000],lev[56000],gap[56000];
int ISAP(int vs,int vt)
{
    int v,i,u,maxf=0,aug,minl; bool f;
    gap[0]=vt-vs+1; u=vs;
    while (lev[vs]<vt)
      {
        f=false;
        for (v=point[u];v!=0;v=next[v])
          if (lev[u]==lev[a[v].v]+1&&a[v].c>0)
            {f=true; break;}
        if (f)
          {
            pre[a[v].v]=v;
            u=a[v].v;
            if (u==vt)
              {
                aug=inf;
                for (i=v;i!=0;i=pre[a[i].u])
                  if (aug>a[i].c)
                    aug=a[i].c;
                maxf+=aug;
                for (i=v;i!=0;i=pre[a[i].u])
                  {
                    a[i].c-=aug;
                    a[i^1].c+=aug;
                  }
                u=vs;
              }
          }
        else
          {
            minl=vt;
            for (i=point[u];i!=0;i=next[i])
              if (minl>lev[a[i].v]&&a[i].c>0)
                minl=lev[a[i].v];
            gap[lev[u]]--;
            if (gap[lev[u]]==0) break;
            lev[u]=minl+1;
            gap[lev[u]]++;
            if (u!=vs) u=a[pre[u]].u;  
          } 
      }
    return maxf;
}
int main()
{
    int i,x,y,c,ans,sum=0;
    freopen("profit9.in","r",stdin);
    freopen("profit.out","w",stdout);
    scanf("%d%d",&n,&m);
    e=1;
    for (i=1;i<=n;++i)
      {
        scanf("%d",&p[i]);
        e++; 
        next[e]=point[i]; point[i]=e; a[e].u=i; a[e].v=n+m+1; a[e].c=p[i];
        e++;
        next[e]=point[n+m+1]; next[n+m+1]=e; a[e].u=n+m+1; a[e].v=i; a[e].c=0;
      }
    for (i=1;i<=m;++i)
      {
        scanf("%d%d%d",&x,&y,&c); sum+=c;
        e++;
        next[e]=point[0]; point[0]=e; a[e].u=0; a[e].v=n+i; a[e].c=c;
        e++;
        next[e]=point[n+i]; point[n+i]=e; a[e].u=n+i; a[e].v=0; a[e].c=0;
        e++;
        next[e]=point[n+i]; point[n+i]=e; a[e].u=n+i; a[e].v=x; a[e].c=inf;
        e++;
        next[e]=point[x]; point[x]=e; a[e].u=x; a[e].v=n+i; a[e].c=0;
        e++;
        next[e]=point[n+i]; point[n+i]=e; a[e].u=n+i; a[e].v=y; a[e].c=inf;
        e++;
        next[e]=point[y]; point[y]=e; a[e].u=y; a[e].v=n+i; a[e].c=0;
      }
   ans=ISAP(0,n+m+1);
   printf("%d\n",sum-ans);
   fclose(stdin); fclose(stdout);
}

Orz神犇仰慕不能

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值