HDU 1532Drainage Ditches(最大流模板题 ISAP)

Drainage Ditches

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 11306    Accepted Submission(s): 5328

Problem Description

Every time it rains on Farmer John‘s fields, a pond forms over Bessie‘s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage
ditches so that Bessie‘s clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into
that ditch.

Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.

Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.

Input

The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections
points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water
will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.

Output

For each case, output a single integer, the maximum rate at which water may emptied from the pond.

Sample Input

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10

Sample Output

50

Source

USACO 93

题大意:给出边数N,点数M,每条边都是单向的,问从1点到M的最大流是多少。

方法一:ISAP

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype __int64

const int MAXN = 100010;
const int MAXM = 400010;
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
//预处理eNode点到所有点的最短距离
void BFS(int sNode, int eNode){
    queue<int>q;
    memset(gap,0,sizeof(gap));
    memset(dis,-1,sizeof(dis));
    gap[0]=1;
    dis[eNode]=0;
    q.push(eNode);
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to;
            if(dis[v]==-1){
                dis[v]=dis[u]+1;
                gap[dis[v]]++;
                q.push(v);
            }
        }
    }
}
int S[MAXN];    //路径栈,存的是边的id号
captype maxFlow_sap(int sNode,int eNode, int n){
    BFS(sNode, eNode);              //预处理eNode到所有点的最短距离
    if(dis[sNode]==-1) return 0;    //源点到不可到达汇点
    memcpy(cur,head,sizeof(head));

    int top=0;  //栈顶
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=0; i<top; i++)    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[S[i]].cap-edg[S[i]].flow){
                Min=edg[S[i]].cap-edg[S[i]].flow;
                inser=i;
            }
            for(int i=0; i<top; i++){
                edg[S[i]].flow+=Min;
                edg[S[i]^1].flow-=Min;  //可回流的边的流量
            }
            ans+=Min;
            top=inser;  //从这条可增流的路中的流量瓶颈 边的上一条边那里是可以再增流的,所以只从断流量瓶颈 边裁断
            u=edg[S[top]^1].to;  //流量瓶颈 边的起始点
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=i;
                break;
            }
        }
        if(flag){
            S[top++] = cur[u];  //加入一条边
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next){
        if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }}
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;      //如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[S[--top]^1].to;  //退一条边

    }
    return ans;
}
int main(){
    int n,m,u,v;
    captype c;
    while(scanf("%d%d",&m,&n)>0){
        init();
        while(m--){
            scanf("%d%d%I64d",&u,&v,&c);
            addEdg(u,v,c);
        }
        printf("%I64d\n",maxFlow_sap(1,n,n));
    }
}

方法二:压入重标记push_relabel

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype __int64
const int N  = 210;
const int MAX= 1<<30;

struct EDG{
    int to,nxt;
    captype c;  //每条边的残留量
}edg[N*N];
int head[N],eid;
captype vf[N];     //顶点的剩余流量
int h[N];      //顶点的高度
//int n;         //顶点个总个数,包含源点与汇点

int min(int a,int b){return a>b?b:a; }
void init(){
    memset(head,-1,sizeof(head));
    eid=0;
}
//添加 有向边
void addEdg(int u , int v, captype c){
    edg[eid].to=v; edg[eid].nxt=head[u]; edg[eid].c=c; head[u]=eid++;
    edg[eid].to=u; edg[eid].nxt=head[v]; edg[eid].c=0; head[v]=eid++;
}
captype maxFlow(int sNode,int eNode,int n){//源点与汇点
    captype minh,ans=0;
    queue<int>q;

    memset(h,0,sizeof(h));
    memset(vf,0,sizeof(vf));
    h[sNode]=n+1;   //源点的高度
    vf[sNode]=MAX;  //源点的余流

    q.push(sNode);
    while(!q.empty()){
        int u=q.front(); q.pop();
        minh=MAX;

        for(int i=head[u]; i!=-1; i=edg[i].nxt){
            int v=edg[i].to;

            captype fp;
            if(edg[i].c<vf[u])fp=edg[i].c;
            else fp=vf[u];

            if(fp>0 ){
                minh=min(minh, h[v]);
                if(u==sNode || h[u]==h[v]+1){
                    edg[i].c-=fp;
                    edg[i^1].c+=fp; //反向边,给个反回的通道
                    vf[u]-=fp;
                    vf[v]+=fp;
                    if(v==eNode) ans+=fp;   //当到达汇点时,就加入最大流中
                    if(v!=sNode && v!=eNode )   //只有即不是源点,也不是汇点时才能进队列
                        q.push(v);
                }
            }
            if(vf[u]==0) break; //如果顶点的余流为0,则可以跳出for循环
        }
        //如果不是源点(也非汇点),且顶点仍有余流,则重新标记 高度+1 入队
        //这里赋值为最低的相邻顶点的高度高一个单位,也可以简单的在原高度+1
        if(u!=sNode && vf[u]>0){
            h[u] = minh + 1;
            q.push(u);
        }
    }
    return ans;
}
int main(){
    int n,m,u,v;
    captype c;
    while(scanf("%d%d",&m,&n)>0){
        init();
        while(m--){
            scanf("%d%d%I64d",&u,&v,&c);
            addEdg(u,v,c);
        }
        printf("%I64d\n",maxFlow(1,n,n));
    }
}

方法三:EK

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
#define captype __int64
const int N = 205;

captype cap[N][N],f[N][N],rest[N];
int sNode,eNode,pre[N];

void init(){
    memset(f,0,sizeof(f));
    memset(cap,0,sizeof(cap));
}

bool searchPath(int n){//找一条增广路
    bool vist[N]={0};
    queue<int>q;
    int u,v;
    u=sNode; vist[u]=1;
    pre[u]=u; rest[u]=1<<30;
    q.push(u);
    while(!q.empty()){
        u=q.front(); q.pop();
        for(v=1; v<=n; v++)
        if(!vist[v]&&cap[u][v]-f[u][v]>0)
        {
            vist[v]=1; pre[v]=u;
            if(cap[u][v]-f[u][v]>rest[u])
              rest[v]=rest[u];
            else
                rest[v]=cap[u][v]-f[u][v];
            if(v==eNode) return true;
            q.push(v);
        }
    }
    return false;
}
captype maxflow(int s,int t,int n){
    captype ans=0;
    sNode=s; eNode=t;
    while(searchPath(n)){
        ans+=rest[eNode];
        int v=eNode;
        while(v!=sNode){
            int u=pre[v];
            f[u][v]+=rest[eNode];
            f[v][u]-=rest[eNode];//给一个回流的机会
            v=u;
        }
    }
    return ans;
}
int main(){
    int n,m,u,v;
    captype c;
    while(scanf("%d%d",&m,&n)>0){
        init();
        while(m--){
            scanf("%d%d%I64d",&u,&v,&c);
            cap[u][v]+=c;
        }
        printf("%I64d\n",maxflow(1,n,n));
    }
}

时间: 2024-12-19 07:39:44

HDU 1532Drainage Ditches(最大流模板题 ISAP)的相关文章

POJ1273 Drainage Ditches 最大流模板题(dinic)

最大流的模板题 给出边数M,顶点数N 以及每条边的容量 求1到N的最大流 注意可以有重边 邻接矩阵模板: #include<iostream> #include<cstdio> #include<cstring> #define maxx 0x3f3f3f #define M 205 using namespace std; int arc[M][M]; //弧的剩余流量 int level[M]; int n; int min(int a,int b) { retur

hdu 3549 Flow Problem(最大流模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549 Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph. Input The first line of input

[ACM] hdu 3549 Flow Problem (最大流模板题)

Flow Problem Problem Description Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph. Input The first line of input contains an integer T, denoting the nu

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

hdu 2085 数塔 -- dp模板题

数塔 Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少? 已经告诉你了,这是个DP的题目,你能AC吗? Input 输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内. Outp

POJ2135 最小费用最大流模板题

练练最小费用最大流 此外此题也是一经典图论题 题意:找出两条从s到t的不同的路径,距离最短. 要注意:这里是无向边,要变成两条有向边 #include <cstdio> #include <cstring> #define MAXN 1005 #define MAXM 10005 #define INF 0x3f3f3f3f struct Edge { int y,c,w,ne;//c容量 w费用 }e[MAXM*4]; int n,m,x,y,w; int s,t,Maxflow

【网络流#2】hdu 1533 最小费用最大流模板题

嗯~第一次写费用流题... 这道就是费用流的模板题,找不到更裸的题了 建图:每个m(Man)作为源点,每个H(House)作为汇点,各个源点与汇点分别连一条边,这条边的流量是1(因为每个源点只能走一条边到汇点),费用是 从源点走到汇点的步数,因为有多个源点与汇点,要建一个超级源点与超级汇点,超级源点与各个源点连一条流量为1,费用为0(要避免产生多余的费用)的边 按照这个图跑一发费用流即可 把代码挂上去,用的是前向星写的 1 #include<cstdio> 2 #include<cstr

poj-1273 Drainage Ditches(最大流基础题)

题目链接: Drainage Ditches Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 67475   Accepted: 26075 Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is cover

hdu4292 Food 最大流模板题

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4292 题意:水和饮料,建图跑最大流模板. 我用的是学长的模板,最然我还没有仔细理解,不过这都不重要直接贴就行了. 下面是AC代码,以后就当做最大流的模板来用了. 代码: #include<cstdio> #include<iostream> using namespace std; const int oo=1e9; const int mm=2e5+5; const int mn=1