网络最大流问题 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 }

 

 

posted @ 2012-09-23 00:25  Ka8  阅读(540)  评论(0)    收藏  举报