• 有上下界的网络流题目泛做


    题目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;
    }
    
  • 相关阅读:
    设计并实现一个漂亮的结婚小站
    Android新特性--ConstraintLayout完全解析
    Android之MainActivity类
    Android app启动activity并调用onCreate()方法时都默默地干了什么?
    Android Studio开发-高效插件强烈推荐
    Android SDK Manager详解
    Android Studio中如何设置颜色拾色器工具
    独立的android开发者开发app如何盈利?
    Android Studio开发常用快捷键
    最强 Android Studio 使用小技巧和快捷键总结
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5368024.html
Copyright © 2020-2023  润新知