POJ 1273 Drainage Ditches(最大流模板)

题目链接:

http://poj.org/problem?id=1273

解题思路:

题目大意:

给你有m个池塘(从1到m开始编号,1为源点,m为汇点)及n条水渠,然后给你这n条水渠所连接的池塘和所能流过的水量,求水渠中所

能流过的水的最大容量。

算法思想:

最大流模板题。。。

AC代码(增广路算法Edmonds_Karp):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int N = 201;
const int INF = 0x3f3f3f3f;
int n,m;
int flow[N][N],cap[N][N],a[N],p[N];
//分别为:flow[u][v]为<u,v>流量、cap[u][v]为<u,v>容量、a[i]表示源点s到节点i的路径上的最小残留量、p[i]记录i的前驱

void Edmonds_Karp(){
    int s = 1;//从1开始
    int sum = 0;//记录最大流量
    queue<int>q;//队列,用bfs找增广路
    while(1){
        memset(a,0,sizeof(a));//每找一次,初始化一次
        a[s] = INF;
        q.push(s);//源点入队
        while(!q.empty()){
            int u = q.front();
            q.pop();
            for(int v = 1; v <= m; v++){
                if(!a[v] && flow[u][v]<cap[u][v]){
                    p[v] = u;
                    q.push(v);
                    a[v] = min(a[u],cap[u][v]-flow[u][v]);//s-v路径上的最小残量
                }
            }
        }
        if(a[m] == 0)//找不到增广路,则当前流已经是最大流
            break;
        sum += a[m];//流加上
        for(int i = m; i != s; i = p[i]){// //从汇点顺着这条增广路往回走
            flow[p[i]][i] += a[m];//更新正向流量
            flow[i][p[i]] -= a[m];//更新反向流量
        }
    }
    printf("%d\n",sum);
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        int v,u,w;
        memset(flow,0,sizeof(flow));//初始化
        memset(cap,0,sizeof(cap));
        while(n--){
            scanf("%d%d%d",&u,&v,&w);
            cap[u][v] += w;//注意图中可能出现相同的边
        }
        Edmonds_Karp();
    }
    return 0;
}


AC代码(空间优化Edmonds_Karp):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

const int N = 201;
const int INF = 0x3f3f3f3f;
int n,m;
int cap[N][N],a[N],p[N];

void Edmonds_Karp(){
    int s = 1;//从1开始
    int sum = 0;//记录最大流量
    queue<int>q;//队列,用bfs找增广路
    while(1){
        memset(a,0,sizeof(a));//每找一次,初始化一次
        a[s] = INF;
        q.push(s);//源点入队
        while(!q.empty()){
            int u = q.front();
            q.pop();
            for(int v = 1; v <= m; v++){
                if(!a[v] && cap[u][v]>0){
                    p[v] = u;
                    q.push(v);
                    a[v] = min(a[u],cap[u][v]);//s-v路径上的最小残量
                }
            }
        }
        if(a[m] == 0)//找不到增广路,则当前流已经是最大流
            break;
        sum += a[m];//流加上
        for(int i = m; i != s; i = p[i]){// //从汇点顺着这条增广路往回走
            cap[p[i]][i] -= a[m];//更新正向流量
            cap[i][p[i]] += a[m];//更新反向流量
        }
    }
    printf("%d\n",sum);
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        memset(cap,0,sizeof(cap));//初始化
        int u,v,w;
        while(n--){
            scanf("%d%d%d",&u,&v,&w);
            cap[u][v] += w;//注意图中可能出现相同的边
        }
        Edmonds_Karp();
    }
    return 0;
}

AC代码(Dinic):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

const int maxn = 210;
const int INF = 0x3f3f3f3f;

struct edge{
    int st,ed;
    int c;
    int next;
}edge[maxn<<1];

int n,m;
int s,t;
int e,head[maxn],d[maxn];

void init(){
    int a,b,c;
    s = 1;t = m;e = 0;
    memset(head,-1,sizeof(head));
    for(int i = 1; i <= n; i++){
        scanf("%d%d%d",&a,&b,&c);
        edge[e].st = a;edge[e].ed = b;edge[e].c = c;
        edge[e].next = head[a];head[a] = e++;
        edge[e].st = b;edge[e].ed = a;edge[e].next = head[b];
        head[b]=e++;
    }
}

int bfs(){
    memset(d,-1,sizeof(d));
    queue<int> q;
    d[s] = 0;
    q.push(s);
    int cur;
    while(!q.empty()){
        cur = q.front();
        q.pop();
        for(int i=head[cur]; i != -1; i = edge[i].next){
            if(d[edge[i].ed]==-1 && edge[i].c){
                d[edge[i].ed] = d[cur]+1;
                q.push(edge[i].ed);
            }
        }
    }
    if(d[t] < 0)
        return 0;
    return 1;
}

int dinic(int x,int flow){
    if(x == t)
        return flow;
    int a;
    for(int i = head[x]; i != -1; i = edge[i].next){
        if(d[edge[i].ed]==d[x]+1 && edge[i].c>0 && (a=dinic(edge[i].ed,min(flow,edge[i].c)))){
            edge[i].c -= a;
            edge[i^1].c += a;
            return a;
        }
    }
    return 0;
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        int ans=0,tt;
        init();
        while(bfs()){
            tt=dinic(1,INF);
            ans += tt;
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值