POJ 1273 Drainage Ditches 网络流模版

题目传送门


网络流模版题,本想水一水,莫想到因为没好好看题给跪了。


题目大意就是 给你一堆水洼地,还有一些水沟,最终让水洼里的水通过水沟流入溪流。

要留意的就是据说会有重边,需要额外处理。(第二次练习 DInic 时发现完全不需要)


再就是要看清题意 “  For any given ditch, water flows in only one direction ” 就是说是有向图,读题的时候专门留意了可是做题的时候却记了个无向图还专门加了个反向。结果坑了半个多小时。。WA了好几次。。深刻检讨!


写了两个代码,虽然都是零毫秒,不过要学习嘛。。

第一种是最简单的寻找增广路 Ford-Fulkerson 算法

#include <cstdio>
#include <cstring>
#include <vector>
#define INF 1<<30
#define N 222
using namespace std;

struct EDGE
{
	int to, cap, rev;
};

vector<EDGE> g[N];
int ff[N][N];
bool used[N];
int n,m;

int dfs(int v,int t,int f){
	if ( v == t ) return f;
	used[v]= true;
	for ( int i(0); i < g[v].size(); i++){
		EDGE &e = g[v][i];
		if ( !used[e.to] && e.cap > 0){
			int d = dfs(e.to, t, min(f,e.cap));
			if ( d > 0){
				e.cap -= d;
				g[e.to][e.rev].cap += d;
				return d;
			}
		}
	}
	return 0;
}

int max_flow(int s,int t){
	int flow = 0;
	while (1){
		memset(used,0,sizeof(used));
		int f = dfs(s,t,INF);
		if (f) flow += f;
		else return flow;
	}
}

void add_edge(int from, int to, int cap){
	g[from].push_back((EDGE){to,cap,g[to].size()});
	g[to].push_back((EDGE){from,0,g[from].size()-1});
}

int main(){
	freopen("in.txt","r",stdin);
	while ( ~scanf("%d%d",&m,&n)){
		for ( int i(0);i<N;i++) g[i].clear();
		memset(ff,0,sizeof(ff));
		while ( m-- ){
			int from,to,cap;
			scanf("%d%d%d",&from,&to,&cap);
			ff[from][to] += cap;
		}
		for ( int i(1);i<=n;i++){
			for ( int j(1); j<=n;j++){
				if ( ff[i][j] ){
					add_edge(i,j,ff[i][j]);
				}
			}
		}
		printf("%d\n",max_flow(1,n));
	}
	return 0;
}


第二种是优化后的 Dinic 算法,方法是 对整个图加了一个分层,每次只找最短的增广路,找不到就一层一层下去。原书《挑战程序设计竞赛(巫泽俊 译)》里还有个 iter[] 表示当前弧,不过没看到用。所以我就擅自去掉了。

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define N 222
#define INF 1<<30
using namespace std;

struct EDGE{
    int to, cap, rev;
};
vector<EDGE> g[N];
queue<int> que;
int dist[N];
int n, m;

void add_edge(int from, int to, int cap){
    g[from].push_back((EDGE){to, cap, g[to].size()});
    g[to].push_back((EDGE){from, 0, g[from].size() - 1});
}

void bfs(int s){
    memset(dist, -1, sizeof(dist));
    while ( !que.empty() ) que.pop();
    dist[s] = 0;
    que.push(s);
    while (!que.empty()){
        int v = que.front();
        que.pop();
        for ( int i(0); i != g[v].size(); i++){
            EDGE &e = g[v][i];
            if ( e.cap > 0 && dist[e.to] < 0){
                dist[e.to] = dist[v] + 1;
                que.push(e.to);
            }
        }
    }
}

int dfs(int v, int t, int f){
    if ( v == t ) return f;
    for  ( int i(0); i != g[v].size(); i++){
        EDGE &e = g[v][i];
        if ( e.cap > 0 && dist[e.to] > dist[v]){
            int d = dfs(e.to, t, min(f, e.cap));
            if ( d > 0){
                e.cap -= d;
                g[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int Dinic(int s, int t){
    int flow = 0;
    while (1){
        bfs(s);
        if (dist[t] < 0) return flow;
        int f;
        while ((f = dfs(s, t, INF)) > 0) flow += f;
    }
}

int main(){
    freopen("in.txt", "r", stdin);
    while ( ~scanf("%d%d", &m, &n)){

        for ( int i(0); i < N; i++) g[i].clear();
        memset(ff,0,sizeof(ff));

        while (m--){
            int from, to, cap;
            scanf("%d%d%d", &from, &to, &cap);
            add_edge(from,to,cap);
        }

        printf("%d\n", Dinic(1, n));
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值