HDU4289Control(最大流)

SAP最大流。。额额额额额额额额,看不懂的说,把题解贴出来吧,好歹也能算个模版。。

HDU-4289-Control

本题可以看成是求A到B的最大流,因为权值在点上,还要进行拆点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define MAXM 100000
#define MAXN 405
#define INF 2e9
struct eee{
    int v,cap,next;
    eee(){};
    eee(int v,int w):v(v),cap(w){}
}edge[MAXM];

int first[MAXN];
int d[MAXN];//距离标号
int pre[MAXN];
int numh[MAXN];//GAP数组
int curfirst[MAXN];//各点当前弧
int flow[MAXN];
int e;
int n;
int m;
int S,D;
void init(){
    memset(first,-1,sizeof(first));
    e=0;
}
void add(int u,int v,int w){
    edge[e]=eee(v,w);
    edge[e].next=first[u];
    first[u]=e++;
    edge[e]=eee(u,0);
    edge[e].next=first[v];
    first[v]=e++;
}
int sap_maxflow(int st,int en){

    int ans=0;
    for(int i=1;i<=n;i++)
    curfirst[i]=first[i];
    memset(d,0,sizeof(d));
    memset(numh,0,sizeof(numh));
    numh[0]=n;
    int i=st;
    bool ok;
    int MIN;
    int aug=INF;

    while(d[st]<n){
        flow[st]=aug;
        ok=false;
        for(int j=curfirst[i];j!=-1;j=edge[j].next){
            if(edge[j].cap&&d[i]==d[edge[j].v]+1){
                ok=true;
                aug=min(aug,edge[j].cap);
                curfirst[i]=j;
                i=edge[j].v;
                pre[i]=j;
                if(i==en){
                    ans+=aug;
                    for(;i!=st;i=edge[pre[i]^1].v){
                        edge[pre[i]].cap-=aug;
                        edge[pre[i]^1].cap+=aug;
                    }
                    aug=INF;
                }
            }
        }
        if(ok)continue;
        MIN=n-1;
        for(int j=first[i];j!=-1;j=edge[j].next)
            if(edge[j].cap&&d[edge[j].v]<MIN){
                MIN=d[edge[j].v];
                curfirst[i]=j;
            }
            if(--numh[d[i]]==0)break;
            d[i]=MIN+1;
            numh[d[i]]++;
            if(i!=st){
                i=edge[pre[i]^1].v;
                aug=flow[i];
            }
        }
    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2){
        scanf("%d%d",&S,&D);
        init();
        int a,b;
        add(0,S,INF);//增加超级源点
        add(D+n,2*n+1,INF);//增加超级汇点
        for(int i=1;i<=n;i++){
            scanf("%d",&a);
            add(i,i+n,a);
            add(i+n,i,a);
        }
        for(int i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            add(a+n,b,INF);
            add(b+n,a,INF);
        }
        S=0;D=2*n+1;
        n=n*2+2;
        printf("%d\n",sap_maxflow(S,D));
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/arbitrary/p/2696214.html