POJ 1273 Drainage Ditches

来源:互联网 发布:浦口行知基地环境 编辑:程序博客网 时间:2024/05/29 13:26

题目链接:Drainage Ditches

解题思路:最大流问题,看了一下午的文章和博客。感觉对最大流有了一个初步的了解。给你一张图,里面部分节点间有容量为C的管道,里面的水流不能大于容量限制,给一个指定的源点和汇点,求汇点可以流入水的最大量。

首先要把整个图转化一下才可以更轻松的解决问题,将所有的边转化为一对边,一个称之为正向边,另一个为反向边。例如u, v节点间有一个容量为C的边,就可以抽象成一个C的正向边u -> v,和一个0的反向边 v -> u。正向边表示可以继续增大这个方向的流向最大值为多少,反向变表示可以减少这个方向的流量,也就是退流,最大值为多少。

其次要将整个图分层,用bfs对于没一个节点给予一个深度值,如果汇点没有被访问到那么就是说汇点没有连通。再在这个分层的图中找到一条严格按照深度增加的路径通往汇点,看这条路径上面的流量可否增加。(这里用DFS,也可以自己模拟栈)重复分层,因为之前有些满流量的边被删去了,所以这里新建的图汇点的层数会有变化,这里会找到新的路径,如果路径找不到,说明所有连向汇点的边已经全部满流量了,这是就可以输出了。否则继续此过程。

PS:这里说的可能不是很严谨,但是是我自己的领悟,其他的东西可以看代码。

DINIC算法 复杂度为O(n^2 * m)

#include<stdio.h>#include<string.h>#include<queue>#include<vector>#define INF 0x5fffffff#define MAX 210using namespace std;typedef struct A{int s, e, c;A(){}A(int a, int b, int d){s = a, e = b, c = d;}}edge;vector<edge> Map[MAX];int dist[MAX];bool vis[MAX];queue<int> que;int n, m, s, e, c;void addedge(int u, int v, int c){//增加边,这里将一条边拆分为两条Map[u].push_back(edge(u, v, c));//正向边Map[v].push_back(edge(v, u, 0));//反向边}int minNum(int a, int b){return a < b ? a : b;}void bfs(){//这里给图中每一个节点标记深度值distint i, j, k;memset(dist, 0, sizeof(dist));memset(vis, false, sizeof(vis));while(!que.empty()) que.pop();que.push(1);vis[1] = true;while(!que.empty()){int s = que.front();que.pop();for(i = 0; i < Map[s].size(); i++){if(!vis[Map[s][i].e] && Map[s][i].c){//这里必须有容量才能表示这条边相通,可以再流过水流que.push(Map[s][i].e);dist[Map[s][i].e] = dist[s] + 1;//深度 + 1vis[Map[s][i].e] = true;//状态标记}}}}int dfs(int u, int ret){//u为当前的节点 ret为当前可以增加的流量int i, j, ans = 0;if(u == m){return ret;}for(i = 0; i < Map[u].size(); i++){//edge tem = Map[u][i];if(Map[u][i].c && dist[Map[u][i].e] == dist[u] + 1){int aa = minNum(ret, Map[u][i].c);//一条路线上要保持每条管道内的流量不超过流量限制int dd = dfs(Map[u][i].e, aa);Map[u][i].c -= dd;//如果可以增加这里要在正向边减去相应的值for(j = 0; j < Map[Map[u][i].e].size(); j++){//反向边要加上这个值if(Map[Map[u][i].e][j].e == u){Map[Map[u][i].e][j].c += dd;break;}}ret -= dd;//此点流过最大的流量值ans += dd;//累计此点变化的流量值}}return ans;}int maxflow(){int ret = 0;while(true){//每深搜一次都要在标记一次深度值bfs();if(!vis[m]){return ret;}ret += dfs(1, INF);}} int main(){int i, j, k;//freopen("in.txt", "r", stdin);while(scanf("%d%d", &n, &m) != EOF){for(i = 0; i < MAX; i++){Map[i].clear();}for(i = 0; i < n; i++){scanf("%d%d%d", &s, &e, &c);addedge(s, e, c);}int tem = maxflow();printf("%d\n", tem);}return 0;}


 

原创粉丝点击