zoukankan      html  css  js  c++  java
  • 有上下界的网络流题目泛做

    题目1 ZOJ2314 无源汇可行流

    题目大意:

    给一张有向图,每条边有容量上界可容量下界,求是否有可行流?

    如果有,输出每条边的流量。

    算法讨论:

    首先,计算出每个点的M(i)值,就是流入下界和-流出下界和,如果M(i)小于0,就从i向T连-M(i)的边,如果M(i)大于0,就从S向i连M(i)的边。

    同时原图中的边的容量为上界减下界。跑一遍从S到T的最大流。

    判断是否有可行流的方法:如果所有与S相连的出边都满流,则说明有可行流。否则没有。

    每条边流量的值 = 这条边的流量下界 + 其反向边的流量。

    代码:

    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    
    using namespace std;
    
    const int N = 200 + 5;
    const int M = 40000 + 5;
    const int oo = 0x3f3f3f3f;
    
    int n, m;
    int d[N], low[M];
    
    struct Edge {
      int from, to, cap, flow;
      Edge(int u = 0, int v = 0, int cp = 0, int fw = 0):
    	from(u), to(v), cap(cp), flow(fw) {}
    };
    
    struct Dinic {
      int n, mm, s, t;
      int dis[N], cur[N], que[N * 5];
      bool vis[N];
      vector <Edge> edges;
      vector <int> G[N];
    
      void clear() {
    	for(int i = 0; i <= n; ++ i) G[i].clear();
    	edges.clear();
      }
    
      void insert(int from, int to, int cap) {
    	edges.push_back((Edge){from, to, cap, 0});
    	edges.push_back((Edge){to, from, 0, 0});
    	mm = edges.size();
    	G[from].push_back(mm - 2);
    	G[to].push_back(mm - 1);
      }
    
      bool bfs() {
    	int head = 1, tail = 1;
    	memset(vis, false, sizeof vis);
    	dis[s] = 0; vis[s] = true; que[head] = s;
    	while(head <= tail) {
    	  int x = que[head];
    	  for(int i = 0; i < (signed) G[x].size(); ++ i) {
    		Edge &e = edges[G[x][i]];
    		if(!vis[e.to] && e.cap > e.flow) {
    		  vis[e.to] = true;
    		  dis[e.to] = dis[x] + 1;
    		  que[++ tail] = e.to;
    		}
    	  }
    	  ++ head;
    	}
    	return vis[t];
      }
    
      int dfs(int x, int a) {
    	if(x == t || a == 0) return a;
    	int flw = 0, f;
    	for(int &i = cur[x]; i < (signed) G[x].size(); ++ i) {
    	  Edge &e = edges[G[x][i]];
    	  if(dis[e.to] == dis[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
    		e.flow += f; edges[G[x][i] ^ 1].flow -= f; a -= f; flw += f;
    		if(a == 0) break;
    	  }
    	}
    	return flw;
      }
    
      void mx(int s, int t) {
    	this->s = s; this->t = t;
    	int flw = 0;
    	while(bfs()) {
    	  memset(cur, 0, sizeof cur);
    	  flw += dfs(s, oo);
    	}
      }
    
      void getans() {
    	bool flag = true;
    	for(int i = 0; i < (signed) G[0].size(); ++ i) {
    	  Edge e = edges[G[0][i]];
    	  if(e.cap - e.flow > 0) flag = false;
    	}
    	if(!flag) puts("NO");
    	else {
    	  puts("YES");
    	  for(int i = 0; i < m * 2; i += 2) {
    		printf("%d
    ", low[(i + 2) >> 1] + edges[i ^ 1].cap - edges[i ^ 1].flow);
    	  }
    	}
      }
    }net;
    
    int main() {
      int t, u, v, l, r;
      bool flag = false;
      scanf("%d", &t);
      while(t --) {
    	if(flag) puts("");
    	else flag = true;
    	scanf("%d%d", &n, &m);
    	net.clear(); net.n = n + 1;
    	for(int i = 1; i <= m; ++ i) {
    	  scanf("%d%d%d%d", &u, &v, &l, &r);
    	  d[u] -= l; d[v] += l; low[i] = l;
    	  net.insert(u, v, r - l);
    	}
    	for(int i = 1; i <= n; ++ i) {
    	  if(d[i] > 0) net.insert(0, i, d[i]);
    	  else if(d[i] < 0) net.insert(i, n + 1, -d[i]);
    	}
    	net.mx(0, n + 1);
    	net.getans();
    	memset(d, 0, sizeof d);
      }
      return 0;
    }
    

    题目2 SGU 176 有源汇最小流

    题目大意:

    给一张图和每条边的一个容量上限,还有一个参数,如果参数是1,则要求这条边必须满流,否则不做要求,求1->n最小流。

    算法讨论:

    如果必须满流,则是上下界都是流量,如果不做要求,则下界是0,上界是流量。

    转化后,先求出每个点的M(i)值,对于M(i)的连边还是像上面一样,同时原图中上下界都是容量的边则不用连边了,下界是0的连容量为流量的边。

    如此连边后,从超级源点S向超级汇点T跑一次MaxFlow,然后加一条从n->1流量为正无穷的边,再从S向T流一次MaxFlow。

    对于答案,先判断是否有可行流,就是与超级源直接相连的边全部满流,说明有可行流。

    那么最小流的流量就是从n->1反向边的流量。

    那么每个边的流量要么是其容量,要么是其相反边的流量。所以对于每条边要记录一个编号,方便更新答案时使用。

    代码:

    /*
    以此代码纪念我们的相识。
    河北 鹿泉一中 NOC竞赛
    */
    
    #include <cstdlib>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    const int N = 100 + 5;
    const int M = 10000 + 5;
    const int oo = 0x3f3f3f3f;
    
    int n, m, d[N], tmp;
    int ans[M];
    
    struct Edge {
      int from, to, cap, flow, id;
      Edge(int u=0, int v=0, int cp=0, int fw=0, int id=0):
    	from(u), to(v), cap(cp), flow(fw), id(id) {}
    };
    
    struct Dinic {
      int n, mm, s, t;
      int dis[N], que[N * 100], cur[N];
      bool vis[N];
      vector <Edge> edges;
      vector <int> G[N];
    
      void add(int from, int to, int cap, int id) {
    	edges.push_back(Edge(from, to, cap, 0, id));
    	edges.push_back(Edge(to, from, 0, 0, 0));
    	mm = edges.size();
    	G[from].push_back(mm - 2);
    	G[to].push_back(mm - 1);
      }
    
      bool bfs() {
    	int head = 1, tail = 1;
    	memset(vis, false, (n + 2) * sizeof (bool));
    	dis[s] = 0; vis[s] = true; que[head] = s;
    	while(head <= tail) {
    	  int x = que[head];
    	  for(int i = 0; i < (signed)G[x].size(); ++ i) {
    		Edge &e = edges[G[x][i]];
    		if(!vis[e.to] && e.cap > e.flow) {
    		  vis[e.to] = true;
    		  dis[e.to] = dis[x] + 1;
    		  que[++ tail] = e.to;
    		}
    	  }
    	  ++ head;
    	}
    	return vis[t];
      }
    
      int dfs(int x, int a) {
    	if(x == t || a == 0) return a;
    	int flw = 0, f;
    	for(int &i = cur[x]; i < (signed) G[x].size(); ++ i) {
    	  Edge &e = edges[G[x][i]];
    	  if(dis[e.to] == dis[x] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
    		e.flow += f; edges[G[x][i] ^ 1].flow -= f; a -= f; flw += f;
    		if(a == 0) break;
    	  }
    	}
    	return flw;
      }
    
      int mx(int s, int t) {
    	this->s = s; this->t = t;
    	int flw = 0;
    	while(bfs()) {
    	  memset(cur, 0, sizeof cur);
    	  flw += dfs(s, oo);
    	}
    	return flw;
      }
    
      void getans() {
    	bool flag = false;
    	for(int i = 0; i < (signed) G[0].size(); ++ i) {
    	  Edge e = edges[G[0][i]];
    	  if(e.cap - e.flow > 0) {
    		flag = true; break;
    	  }
    	}
    	if(flag) puts("Impossible");
    	else {
    	  for(int i = 0; i < (signed) G[n - 1].size(); ++ i) {
    		Edge e = edges[G[n - 1][i]];
    		if(e.to == 1) {
    		  printf("%d
    ", edges[G[n - 1][i] ^ 1].cap - edges[G[n - 1][i] ^ 1].flow);
    		  break;
    		}
    	  }
    	  for(int i = 0; i < 2 * tmp; i += 2) {
    		ans[edges[i].id] = edges[i ^ 1].cap - edges[i ^ 1].flow;
    	  }
    	  for(int i = 1; i <= m; ++ i) {
    		if(i - 1) printf(" %d", ans[i]);
    		else printf("%d", ans[i]);
    	  }
    	}
      }
    }net;
    
    int main() {
      int u, v, c, type;
      scanf("%d%d", &n, &m);
      net.n = n + 1;
      for(int i = 1; i <= m; ++ i) {
    	scanf("%d%d%d%d", &u, &v, &c, &type);
    	if(type) {
    	  d[u] -= c; d[v] += c; ans[i] = c;
    	}
    	else net.add(u, v, c, i), ++ tmp;
      }
      for(int i = 1; i <= n; ++ i) {
    	if(d[i] < 0) net.add(i, n + 1, -d[i], 0);
    	else if(d[i] > 0) net.add(0, i, d[i], 0);
      }
      net.mx(0, n + 1);
      net.add(n, 1, oo, 0);
      net.mx(0, n + 1);
      net.getans();
      return 0;
    }
    
  • 相关阅读:
    HDU 1010 Tempter of the Bone(DFS剪枝)
    HDU 1013 Digital Roots(九余数定理)
    HDU 2680 Choose the best route(反向建图最短路)
    HDU 1596 find the safest road(最短路)
    HDU 2072 单词数
    HDU 3790 最短路径问题 (dijkstra)
    HDU 1018 Big Number
    HDU 1042 N!
    NYOJ 117 求逆序数 (树状数组)
    20.QT文本文件读写
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5368024.html
Copyright © 2011-2022 走看看