bzoj網絡流


近期看了一些bzoj的網絡流,深感智商不夠。不過對於網絡流又有了進一步的理解。

還是mark一下吧。

獻上幾篇論文:1)最小割模型在信息學競賽中的應用》

                    2)《淺析一類最小割問題》

 

1、bzoj1066(最大流)

題意:戳這里

思路:很明顯拆點最大流模型,然后對於每個點每個高度流量限為1,那么根據最大流即為可以出去的蜥蜴的數量。

2、bzoj1077(費用流)

戳這里

3.bzoj1391(最小割)

題意:戳這里

思路:有點像最大權閉合圖。。可以利用最小割的性質建圖:

        <S,任務,收益>

        <機器,T,購買費用>,<任務,機器,租用費用>

        這樣,如果與T相連的邊為割,表示購買機器花費更小。

        如果與S相連的邊為割,表示任務花費太大,不做任務更優(收益為0)。

        如果<任務,機器>邊為割,表示任務花費太大,不做任務更優(收益為0)。

        最后總收益-最大流即為答案

4、bzoj1412(最小割)

題意:有一些格子里是狼,一些里是羊,一些是空的,要使狼和羊的格子不相通,至少要堵多少條邊界。

思路:很明顯的最小割

5、bzoj1433(二分圖匹配)

題意:戳這里

思路:需要床位的為一邊,提供床位的為一邊,認識連一條邊(包括自己跟自己),然后就是一個二分圖最大匹配。

6、bzoj1475(最大點獨立集)

題意:戳這里

思路:Amber論文里講到的題目,很明顯可以看出是個二分圖模型。。

        但是不容易看出是求最大點權獨立集。那么構圖就很顯然了。

7、bzoj1497(最大密度子圖)

題意:戳這里

思路:可以轉化成最小割。具體看Amber論文。

8、bzoj1520(費用流)

題意:戳這里

思路:很明顯的最小費用流

9、bzoj1532(最大流+二分)

題意:戳這里

思路:二分最大分數score,那么

        <S,人,score>,<人,比賽,1>,<比賽,T,1>

        判斷流量flow = m

10、bzoj1565(tarjan+最大權閉合圖)

題意:戳這里

思路:首先先把保護關系建立有向邊,那么如果出現環的話,環里面的所有點,包括他能保護得點都不能取。。

         那么剩下的圖再進行最大權閉合圖的構圖

code:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define M0(a) memset(a, 0, sizeof(a))
  4 #define Inf 0x3fffffff
  5 const int maxn = 1000;
  6 const int maxm = 800010;
  7 struct oo{
  8     int y, f, next;
  9 };
 10 struct MaxFlow{
 11        int n, S, T, tot;
 12        int son[maxn], dist[maxn], gap[maxn];
 13        oo e[maxm];
 14        int sap(int x, int aug){
 15            if (x == T) return aug;
 16            int mind = n;
 17            int sum = 0, f;
 18            for (int p = son[x]; p != -1; p = e[p].next){
 19                   int y = e[p].y;
 20                   if (dist[y] + 1 == dist[x] && e[p].f){
 21                        f = sap(y, min(e[p].f, aug - sum));
 22                        e[p].f -= f;
 23                        e[p^1].f += f;
 24                        sum += f;
 25                        if (sum == aug || dist[S] >= n) return sum;
 26                   }
 27                   if (e[p].f) mind = min(mind, dist[y]);
 28            }
 29            if (!sum){
 30                if (!(--gap[dist[x]])) dist[S] = n;
 31                ++gap[dist[x] = mind + 1];
 32            }
 33            return sum;
 34        }
 35        void add(int x, int y, int f){
 36             e[tot].y = y; e[tot].f = f;
 37             e[tot].next = son[x]; son[x] = tot++;
 38             e[tot].y = x; e[tot].f = 0;
 39             e[tot].next = son[y]; son[y] = tot++;
 40        }
 41 
 42        void init(int S, int T, int n){
 43             memset(son, -1, sizeof(son));
 44             tot = 0;
 45             this->S = S, this->T = T, this->n = n;
 46        }
 47        int maxflow(){
 48             M0(gap);
 49             M0(dist);
 50             gap[0] = n;
 51             int ans = 0;
 52             while (dist[S] < n) ans += sap(S, Inf);
 53             return ans;
 54        }
 55 } F;
 56 vector<int> e[maxn];
 57 int n, m, sum;
 58 int score[31][31], use[31 * 31], vis[31 * 31];
 59 //vector<pair<int, int> > pre[35][35]; 
 60 void init(){
 61      for (int i = 0; i <= n * m; ++i)
 62            e[i].clear();
 63 //     for (int i = 0; i <= n; ++i)
 64 //         for ()
 65      int k, x, y;
 66      int cur = 0;
 67      for (int i = 1; i <= n; ++i)
 68          for (int j = 1; j <= m; ++j){
 69               scanf("%d%d", &score[i][j], &k);
 70               ++cur;
 71               while (k--){
 72                    scanf("%d%d", &x, &y);
 73                    e[cur].push_back(x*m+y+1);
 74               }
 75               if (j > 1) e[cur].push_back(cur-1);
 76          }
 77         
 78 }
 79 /*** tarjan-begin ***/
 80 int top, Index, dfn[maxn], low[maxn], stk[maxn], col[maxn], cnt;
 81 bool insta[maxn];
 82 vector<int> co[maxn];
 83 void tarjan(int u){
 84     dfn[u] = low[u] = ++Index;
 85     stk[++top] = u;
 86     insta[u] = true;
 87     int v;
 88     for (int i = 0; i < (int)e[u].size(); ++i){
 89         v = e[u][i];
 90         if (!dfn[v]){
 91             tarjan(v);
 92             low[u] = min(low[v], low[u]);   
 93         } 
 94         else if (insta[v]) low[u] = min(low[u], dfn[v]);
 95     }
 96     if (dfn[u] == low[u]){
 97         ++cnt;
 98         while (1){
 99             col[stk[top]] = cnt;
100             insta[stk[top]] = false;
101             if (stk[top--] == u) break;    
102         }        
103     }
104 }
105 
106 void tarjan(){
107     M0(dfn), M0(low), M0(insta), M0(col);
108     top = cnt = Index = 0;
109     for (int i = 1; i <= n*m; ++i)
110         if (!dfn[i]) tarjan(i);
111     for (int i = 1; i <= n * m; ++i)
112          co[i].clear();
113     for (int i = 1; i <= n * m; ++i)
114          co[col[i]].push_back(i);
115 }
116 /***tarjan-end ***/
117 
118 void dfs(const int u){
119     if (vis[u]) return;
120     vis[u] = 1;
121     for (int i = 0; i < (int)e[u].size(); ++i)
122           dfs(e[u][i]);
123 }
124 
125 void solve(){
126      tarjan();
127      M0(use);
128      for (int i = 1; i <= cnt; ++i)
129          if ((int)co[i].size() > 1){
130                 for (int j = 0; j < (int)co[i].size(); ++j)
131                   use[co[i][j]] = 1;
132          }
133      M0(vis);
134      for (int i = 1; i <= n * m; ++i)
135          if (use[i] && !vis[i]) dfs(i);
136      int S = 0, T = n *m + 1;
137      F.init(S, T, T + 1);
138      int cur = sum = 0;
139      for (int i = 1; i <= n; ++i)
140           for (int j = 1; j <= m; ++j){
141                ++cur;
142                if (vis[cur]) continue; 
143                if (score[i][j] >= 0) 
144                       F.add(S, cur, score[i][j]), sum += score[i][j];
145                else
146                       F.add(cur, T, -score[i][j]); 
147                for (int k = 0; k < (int)e[cur].size(); ++k)
148                       F.add(e[cur][k], cur, Inf);
149           }
150      int ans = sum - F.maxflow();
151      printf("%d\n", ans);
152 }
153 
154 int main(){
155 //     freopen("a.in", "r", stdin);
156      while (scanf("%d%d", &n, &m) != EOF){
157           init();
158           solve();     
159      }
160 }
View Code

 

11、bzoj1585(最小割)

題意:戳這里

思路:

拆點最小割,保證每個點流量為1

<S, 1, INF>

提到的點x : <x', T, INF>

對於每個點x,為1或是提到的點: <x,x',INF>

對於每個點x,不為1且不是提到的點:<x,x',1>

對於原圖每條邊x->y: <x', y, INF>和 <y', x, INF>

最大流即為答案。。

ps..這一題跟usaco原題改動有點大。。害我做原題時進坑了。。

12、bzoj1711(最大流)

題意:戳這里

思路:三分圖匹配,記得中間那個點要拆點限流量為1

13、bzoj1741(最小點覆蓋)

題意:戳這里

思路:把行列抽象出來成為一個二分圖,有小行星就連一條邊。那么題目就等價與求出最小的點覆蓋所有的遍。

14、bzoj1779(拆點最大流)

題意:戳這里

思路:好像還不是很理解。。過后補上。

15、bzoj1797(最小割+tarjan)

題意:戳這里

思路:首先跑一邊最大流。然后在殘余圖中進行tarjan縮點。

         那么對於所有滿流邊:

              如果連接S,T兩個強聯通分量,那么一定是在最小割里。

              如果連接兩個不同的強聯通分量,可能出現在最小割里。

16、bzoj1822(二分+最大流)

題意:戳這里

思路:二分時間t,那么就可以算出在這個時間內每個巫妖可以攻擊的數目。

         然后建圖:

         <S,  巫妖, 可攻擊數目>,<巫妖,可攻擊到的小精靈, 1>,<小精靈, T , 1>

          最后判斷最大流是否為小精靈個數

          比較麻煩的是判斷巫妖是否攻擊到小精靈,需要一點計算幾何知識。

17、bzoj1834(網絡流模板)

題意:戳這里

思路:<S, 1, K>, 先跑一邊最大流,然后在殘余網絡的每條邊加上一條流量Inf費用為擴容費用的邊

18、bzoj1877(最小費用最大流)

題意:戳這里

思路:拆點,然后就是經典構圖了

19、bzoj1927(最小費用最大流)

戳這里

20、bzoj1934(最小割)

題意:戳這里

思路:分集合很典型的最小割的應用

         最初選擇睡午覺 <S, i, 1>

         最初選擇不睡午覺 <i, T, 1>

         i與j為好友, <i, j, 1> <j, i, 1> 

         最小割即為答案。。這應該是pty大神論文最簡單的應用吧

21、bzoj1937(二分圖最大權匹配問題)

題意:戳這里

思路:把所有邊分為樹邊與非樹邊,那么對於費樹邊i,連接u,v

         權值wi>=wj(所有u,v路徑上的邊j),所以非樹邊只有可能變大,樹邊只有可能變小

         即,對於非樹邊i即路徑上的任意樹邊j:

              wi + di >= wj - dj

         => di + dj >= wj - wi

        wj-wi為定值,那么等式幾乎就跟最大權匹配的頂標的式子一樣了。。

         套用最大權匹配km算法。。

        本來想用費用流,一想到邊很多就慫了。。

22、bzoj2039(最小割)

戳這里

23、bzoj2127(最小割)

題意:戳這里

思路:可利用二元關系建圖:

         <S, A, w1/2>,<A, T, w2/2>

        <S, B, w1/2> , <B,T,w2/2>,

         <A, B, (w1+w2)/2>, <B, A, (w1 + w2)/2>

       為防止出現小數,可將所有流量都流量*2,最后/2即可。

        答案即為sum(喜悅值)- flow

 

未完待續。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM