网络最大流问题 Dinic多路增广
网络最大流问题,就是一个有向图G=(v,e)每条边的边权可以想象成一个管道的宽度,水流从起始点流入汇点,即使你之前的流水量很大,但一条通路中最细的管道才是这条路的最终水量,类似于木桶效应,求的是到汇点最大流量是多少。那么具体解决方法就是建造两个图,层次图和剩余图,层次图先用广搜把每个点标上level,从低级流向高级,剩余图如果是从低级向高级,表示的是这条管道还剩多少流量可以使用,反向的从高级流向低级表示的是高级点能够消耗多少流量。也就是两个量相加总是这条管道的宽度。
然后便是一次又一次的从起始点流向汇点的搜索,知道无路可搜。
嗯刚学的网络最大流,发现dinic多路增广着实好用,比Dinic优化了不少,其主要原理是在找到汇点后不全部return而是继续搜索,期中可增广的流量用total保存,每次拿剩余量-total就是这次所利用的流量。Find函数结束前一定别忘了将无剩余量的“废点”删去,也就是将level变为-1。
还有今年的noip可以使用STL对解决问题方面有着极大的帮助,于是我用了下队列容器queue,感觉不错:)
代码如下
Dinic多路增广
1 #include <iostream> 2 #include <queue> 3 using namespace std; 4 5 int N, M, level[10001]; 6 struct edge 7 { 8 int v, f; 9 edge *next, *rev; 10 }e[10001], *V[10001]; 11 12 void init() 13 { 14 int i, x, y, z, top = -1; 15 cin >> N >> M; 16 for (i = 1; i <= M; i++) 17 { 18 cin >> x >> y >> z; 19 edge *p = &e[++top]; 20 edge *q = &e[++top]; 21 p -> v = y;p -> f = z;p -> next = V[x];p -> rev = q;V[x] = p; 22 q -> v = x;q -> f = 0;q -> next = V[x];V[y] = q;q -> rev = p; 23 } 24 } 25 bool mklevel() 26 { 27 int i; 28 queue<int> que; 29 for (i = 1; i <= N; i++) 30 level[i] = -1; 31 level[1] = 0; 32 que.push(1); 33 while (!que.empty()) 34 { 35 int tmp = que.front(); 36 que.pop(); 37 edge *p; 38 for (p = V[tmp];p;p = p -> next) 39 if (p -> f && level[p -> v] == - 1) 40 { 41 que.push(p -> v); 42 level[p -> v] = level[tmp] + 1; 43 } 44 if (level[N] != - 1) 45 return true; 46 } 47 return false; 48 } 49 50 int Find(int r, int key) 51 { 52 if (r == N) 53 return key; 54 edge *p; 55 int d = 0, tot = 0; 56 for (p = V[r]; p && tot < key; p = p -> next) 57 { 58 if (p -> f && level[p -> v] == level[r] + 1) 59 { 60 d = Find(p -> v, min(key - tot, p -> f)); 61 p -> f -= d; 62 p -> rev -> f += d; 63 tot += d; 64 } 65 } 66 if (!tot)level[r] = -1; 67 return tot; 68 } 69 70 int Dinic() 71 { 72 int ret = 0, t; 73 while (mklevel()) 74 while(t = Find(1, INT_MAX)) ret += t; 75 return ret; 76 } 77 78 int main() 79 { 80 init(); 81 cout << Dinic() << endl; 82 system("pause"); 83 return 0; 84 }


浙公网安备 33010602011771号