关于有容量下界的网络可行流问题解决的学习笔记 ZOJ 2314 ZOJ 3229 HDU 3157

白书二代上提到了无源无汇有容量下界网络可行流和有容量下界网络的s-t最大/最小流问题。

但是由于本人智商捉鸡,觉得LRJ大神写的似乎不是很好理解,所以只能找一些题目来帮助自己理解理解了。

这里直说方法,证明。。。不会。

1.无源无汇有容量下界可行流

这个问题的解法在周源的那个论文里讲的很清楚了。

对于每条边,都有一个容量下界b和一个容量上界c,那么这条边实际的可行流量只有c-b,剩下的b必须满流。

对每个点i,求a = sum(流向它的下界流)-sum(从它流出的下界流量)

若a>0,从源点0连一条到i的容量为a的边

若a<0,从i连一条到汇点n+1的容量为-a的边

(我觉得其实这里都是为求自由流做的准备)

然后求一次最大流,若所有从源点出发的点都满流,则有可行流,每条边的可行流为求最大流后的实际流量flow+该边的流量下界b

题目:ZOJ 2314

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 #include <queue>
  6 #define maxn 210
  7 #define INF 100000000
  8 using namespace std;
  9 
 10 struct Edge{
 11     int from,to,cap,flow;
 12 };
 13 
 14 struct Dinic{
 15     int n,m,s,t;
 16     vector<Edge> edges;
 17     vector<int> G[maxn];
 18     bool vis[maxn];
 19     int d[maxn];
 20     int cur[maxn];
 21 
 22     void ClearAll(int n){
 23         for(int i = 0;i < n;i++)    G[i].clear();
 24         edges.clear();
 25     }
 26 
 27     void add_edge(int from,int to,int cap){
 28         edges.push_back((Edge){from,to,cap,0});
 29         edges.push_back((Edge){to,from,0,0});
 30         m = edges.size();
 31         G[from].push_back(m-2);
 32         G[to].push_back(m-1);
 33     }
 34 
 35     bool BFS(){
 36         memset(vis,0,sizeof(vis));
 37         queue<int> Q;
 38         Q.push(s);
 39         vis[s] = 1;
 40         d[s] = 0;
 41         while(!Q.empty()){
 42             int x = Q.front();Q.pop();
 43             for(int i = 0;i < G[x].size();i++){
 44                 Edge& e = edges[G[x][i]];
 45                 if(!vis[e.to] && e.cap > e.flow){
 46                     vis[e.to] = 1;
 47                     d[e.to] = d[x] + 1;
 48                     Q.push(e.to);
 49                 }
 50             }
 51         }
 52         return vis[t];
 53     }
 54 
 55     int DFS(int x,int a){
 56         if(x == t || a == 0)    return a;
 57         int flow = 0,f;
 58         for(int &i = cur[x];i < G[x].size();i++){
 59             Edge& e = edges[G[x][i]];
 60             if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap-e.flow))) > 0){
 61                 e.flow += f;
 62                 edges[G[x][i]^1].flow -= f;
 63                 flow += f;
 64                 a -= f;
 65                 if(a == 0)  break;
 66             }
 67         }
 68         return flow;
 69     }
 70 
 71     int Maxflow(int s,int t){
 72         this->s = s;this->t = t;
 73         int flow = 0;
 74         while(BFS()){
 75             memset(cur,0,sizeof(cur));
 76             flow += DFS(s,INF);
 77         }
 78         return flow;
 79     }
 80 };
 81 
 82 Dinic g;
 83 int in[maxn],flow[50000],low[50000];
 84 int main()
 85 {
 86     int T,n,m,a,b,c;
 87     scanf("%d",&T);
 88     while(T--){
 89         scanf("%d%d",&n,&m);
 90         memset(in,0,sizeof(in));
 91         g.ClearAll(n+2);
 92         for(int i = 0;i < m;i++){
 93             scanf("%d%d%d%d",&a,&b,&low[i],&c);
 94             in[a] -= low[i];
 95             in[b] += low[i];
 96             g.add_edge(a,b,c-low[i]);
 97         }
 98         for(int i = 1;i <= n;i++){
 99             if(in[i] > 0)   g.add_edge(0,i,in[i]);
100             if(in[i] < 0)   g.add_edge(i,n+1,-in[i]);
101         }
102         g.Maxflow(0,n+1);
103         bool flag = true;
104         for(int i = 0;i < g.G[0].size();i++){
105             //printf("%d %d\n",g.edges[g.G[0][i]].cap,g.edges[g.G[0][i]].flow);
106             if(g.edges[g.G[0][i]].flow != g.edges[g.G[0][i]].cap){
107                 flag = false;
108                 break;
109             }
110         }
111         if(flag){
112             printf("YES\n");
113             for(int i = 0;i < m;i++){
114                 printf("%d\n",low[i] + g.edges[i*2].flow);
115             }
116         }else{
117             printf("NO\n");
118         }
119         printf("\n");
120     }
121     return 0;
122 }
View Code

2.有源汇有下界的最大流问题

(1)首先假设真正的源点和汇点分别为s和t,跟上面一样:

对于每条边,都有一个容量下界b和一个容量上界c,那么这条边实际的可行流量只有c-b,剩下的b必须满流。

对每个点i,求a = sum(流向它的下界流)-sum(从它流出的下界流量)

(2)添加一条从汇点t到源点s,流量为INF的边

(3)对所有的点,根据该a值( a = sum(流向它的下界流)-sum(从它流出的下界流量) )向新构造出的源点SS,汇点TT加边

若a>0,从新源点SS连一条到i的容量为a的边

若a<0,从i连一条到新汇点TT的容量为-a的边

(4)求一次从(SS->TT)的最大流,看从SS出发的边是否全部满流,若不满流则无解

(5)删掉SS、TT这两个点

(6)再做一次(s->t)的最大流,此时各条边上的流量flow+该边的流量下限就是整个网络流量有解时的真实流量

题目:ZOJ 3229

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <cstring>
  5 #include <queue>
  6 #include <algorithm>
  7 #define maxn 1400
  8 #define INF 1000000000
  9 using namespace std;
 10 int g[1010],c[400],D[400];
 11 int L[400][1010],R[400][1010],T[400][1000],task[400];
 12 int in[maxn];
 13 struct Edge{
 14     int from,to,cap,flow;
 15 };
 16 
 17 struct ISAP {
 18   int n, m, s, t;
 19   vector<Edge> edges;
 20   vector<int> G[maxn];
 21   bool vis[maxn];
 22   int d[maxn];
 23   int cur[maxn];
 24   int p[maxn];
 25   int num[maxn];
 26 
 27   void AddEdge(int from, int to, int cap) {
 28     edges.push_back((Edge){from, to, cap, 0});
 29     edges.push_back((Edge){to, from, 0, 0});
 30     m = edges.size();
 31     G[from].push_back(m-2);
 32     G[to].push_back(m-1);
 33   }
 34 
 35   bool BFS() {
 36     memset(vis, 0, sizeof(vis));
 37     queue<int> Q;
 38     Q.push(t);
 39     vis[t] = 1;
 40     d[t] = 0;
 41     while(!Q.empty()) {
 42       int x = Q.front(); Q.pop();
 43       for(int i = 0; i < G[x].size(); i++) {
 44         Edge& e = edges[G[x][i]^1];
 45         if(!vis[e.from] && e.cap > e.flow) {
 46           vis[e.from] = 1;
 47           d[e.from] = d[x] + 1;
 48           Q.push(e.from);
 49         }
 50       }
 51     }
 52     return vis[s];
 53   }
 54 
 55   void ClearAll(int n) {
 56     this->n = n;
 57     for(int i = 0; i < n; i++) G[i].clear();
 58     edges.clear();
 59   }
 60 
 61   int Augment() {
 62     int x = t, a = INF;
 63     while(x != s) {
 64       Edge& e = edges[p[x]];
 65       a = min(a, e.cap-e.flow);
 66       x = edges[p[x]].from;
 67     }
 68     x = t;
 69     while(x != s) {
 70       edges[p[x]].flow += a;
 71       edges[p[x]^1].flow -= a;
 72       x = edges[p[x]].from;
 73     }
 74     return a;
 75   }
 76 
 77   int Maxflow(int s, int t) {
 78     this->s = s; this->t = t;
 79     int flow = 0;
 80     BFS();
 81     memset(num, 0, sizeof(num));
 82     for(int i = 0; i < n; i++) num[d[i]]++;
 83     int x = s;
 84     memset(cur, 0, sizeof(cur));
 85     while(d[s] < n) {
 86       if(x == t) {
 87         flow += Augment();
 88         x = s;
 89       }
 90       int ok = 0;
 91       for(int i = cur[x]; i < G[x].size(); i++) {
 92         Edge& e = edges[G[x][i]];
 93         if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advance
 94           ok = 1;
 95           p[e.to] = G[x][i];
 96           cur[x] = i;
 97           x = e.to;
 98           break;
 99         }
100       }
101       if(!ok) { // Retreat
102         int m = n-1;
103         for(int i = 0; i < G[x].size(); i++) {
104           Edge& e = edges[G[x][i]];
105           if(e.cap > e.flow) m = min(m, d[e.to]);
106         }
107         if(--num[d[x]] == 0) break;
108         num[d[x] = m+1]++;
109         cur[x] = 0;
110         if(x != s) x = edges[p[x]].from;
111       }
112     }
113     return flow;
114   }
115 };
116 
117 ISAP sap;
118 int main()
119 {
120     int n,m;
121     while(scanf("%d%d",&n,&m) == 2){
122         sap.ClearAll(n+m+5);
123         memset(in,0,sizeof(in));
124         for(int i = 1;i <= m;i++)
125             scanf("%d",&g[i]);
126         for(int day = 1;day <= n;day++){
127             scanf("%d%d",&task[day],&D[day]);
128             for(int i = 1;i <= task[day];i++){
129                 int girl_num,l,r;
130                 scanf("%d%d%d",&girl_num,&l,&r);
131                 girl_num++;
132                 T[day][i] = girl_num;
133                 L[day][girl_num] = l;
134                 R[day][girl_num] = r;
135             }
136         }
137         int s = 0,t = n+m+1;
138         int SS = t+1,TT = SS + 1;
139         for(int i = 1;i <= n;i++){
140             for(int j = 1;j <= task[i];j++){
141                 int girl_num = T[i][j];
142                 in[i] -= L[i][girl_num];
143                 in[n+girl_num] += L[i][girl_num];
144                 sap.AddEdge(i,n+girl_num,R[i][girl_num]-L[i][girl_num]);
145             }
146         }
147         for(int i = 1;i <= n;i++){
148             sap.AddEdge(s,i,D[i]);
149         }
150         for(int i = 1;i <= m;i++){
151             in[n+i] -= g[i];
152             in[t] += g[i];
153             sap.AddEdge(n+i,t,INF-g[i]);
154         }
155         sap.AddEdge(t,s,INF);
156         int sum = 0;
157         int tmp = sap.edges.size();
158         for(int i = 0;i <= n+m+1;i++){
159             if(in[i] > 0)   sap.AddEdge(SS,i,in[i]);
160             if(in[i] < 0)   sap.AddEdge(i,TT,-in[i]);
161             if(in[i] > 0)   sum += in[i];
162         }
163         int maxflow = sap.Maxflow(SS,TT);
164         if(maxflow != sum){
165             printf("-1\n\n");
166             continue;
167         }
168         for(int i = tmp;i < sap.edges.size();i++){
169             sap.edges[i].flow = sap.edges[i].cap = 0;
170         }
171         maxflow = sap.Maxflow(s,t);
172         printf("%d\n",maxflow);
173         int cnt = 0;
174         for(int i = 1;i <= n;i++){
175             for(int j = 1;j <= task[i];j++){
176                 printf("%d\n",sap.edges[cnt*2].flow+L[i][T[i][j]]);
177                 cnt++;
178             }
179         }
180         printf("\n");
181     }
182     return 0;
183 }
View Code

3.有源汇有下界的最小流问题

(1)如2中的(1)(3),构造网络………………

(2)这时不能直接添加一条从汇点t到源点s,流量为INF的边!要先求一次(SS->TT)的最大流,求得最大流maxflow记为flow1

(3)添加一条从汇点t到源点s,流量为INF的边

(4)再求一次从(SS->TT)的最大流,求得最大流maxflow记为flow2

(5)假如flow1+flow2==sum(sum就是所有a>0的点的a值的和,就是SS满流情况),有解

(6)此时,最小流就是t->s边上的流量

题目:HDU 3157

代码:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <vector>
  5 #include <queue>
  6 #include <algorithm>
  7 #define maxn 60
  8 #define INF 1000000000
  9 using namespace std;
 10 struct Edge{
 11     int from,to,cap,flow;
 12 };
 13 struct Dinic{
 14     int n,m,s,t;
 15     vector<Edge> edges;
 16     vector<int> G[maxn];
 17     bool vis[maxn];
 18     int d[maxn];
 19     int cur[maxn];
 20     void ClearAll(int n){
 21         for(int i = 0;i < n;i++)    G[i].clear();
 22         edges.clear();
 23     }
 24     void AddEdge(int from,int to,int cap){
 25         edges.push_back((Edge){from,to,cap,0});
 26         edges.push_back((Edge){to,from,0,0});
 27         m = edges.size();
 28         G[from].push_back(m-2);
 29         G[to].push_back(m-1);
 30     }
 31     bool BFS(){
 32         memset(vis,0,sizeof(vis));
 33         queue<int> Q;
 34         Q.push(s);
 35         vis[s] = 1;
 36         d[s] = 0;
 37         while(!Q.empty()){
 38             int x = Q.front();Q.pop();
 39             for(int i = 0;i < G[x].size();i++){
 40                 Edge& e = edges[G[x][i]];
 41                 if(!vis[e.to] && e.cap > e.flow){
 42                     vis[e.to] = 1;
 43                     d[e.to] = d[x] + 1;
 44                     Q.push(e.to);
 45                 }
 46             }
 47         }
 48         return vis[t];
 49     }
 50     int DFS(int x,int a){
 51         if(x == t || a == 0)    return a;
 52         int flow = 0,f;
 53         for(int& i = cur[x];i < G[x].size();i++){
 54             Edge& e = edges[G[x][i]];
 55             if(d[x] + 1 == d[e.to] && (f = DFS(e.to,min(a,e.cap-e.flow))) > 0){
 56                 e.flow += f;
 57                 edges[G[x][i]^1].flow -= f;
 58                 flow += f;
 59                 a -= f;
 60                 if(a == 0)  break;
 61             }
 62         }
 63         return flow;
 64     }
 65     int Maxflow(int s,int t){
 66         this->s = s;this->t = t;
 67         int flow = 0;
 68         while(BFS()){
 69             memset(cur,0,sizeof(cur));
 70             flow += DFS(s,INF);
 71         }
 72         return flow;
 73     }
 74 };
 75 Dinic g;
 76 int in[maxn];
 77 int main()
 78 {
 79     int n,m,s,t,SS,TT,a,b,cir;
 80     char from[10],to[10];
 81     while(scanf("%d%d",&n,&m),n+m){
 82         memset(in,0,sizeof(in));
 83         g.ClearAll(n+5);
 84         s = 0,t = n+1,SS = t+1,TT = SS+1;
 85         int sum = 0;
 86         for(int i = 0;i < m;i++){
 87             scanf("%s%s%d",from,to,&cir);
 88             if(from[0] == '+')  a = s;
 89             else    sscanf(from,"%d",&a);
 90             if(to[0] == '-')    b = t;
 91             else    sscanf(to,"%d",&b);
 92             in[a] -= cir;in[b] += cir;
 93             g.AddEdge(a,b,INF-cir);
 94         }
 95         for(int i = 0;i <= t;i++){
 96             if(in[i] > 0)   g.AddEdge(SS,i,in[i]),sum += in[i];
 97             if(in[i] < 0)   g.AddEdge(i,TT,-in[i]);
 98         }
 99 
100         int flow1 = g.Maxflow(SS,TT);
101         g.AddEdge(t,s,INF);
102         int flow2 = g.Maxflow(SS,TT);
103         if(flow1 + flow2 != sum)    printf("impossible\n");
104         else{
105             int e = g.edges.size() - 2;
106             printf("%d\n",g.edges[e].flow);
107         }
108     }
109     return 0;
110 }
View Code

 

posted @ 2013-08-06 20:15  浙西贫农  阅读(426)  评论(0编辑  收藏  举报