-【網絡流總結】

最大流就不說了。。Dinic。。。
php

發個模板:html

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 210
  9 #define Maxm 10010
 10 #define INF 0xfffffff
 11 
 12 int fa[Maxn],first[Maxn],dis[Maxn];
 13 bool map[Maxn][Maxn];
 14 
 15 struct node
 16 {
 17     int x,y,f,o,next;
 18 };
 19 node t[10*Maxm],tt[10*Maxm];int len;
 20 
 21 int st,ed;
 22 int n,m,k;
 23 
 24 int mymin(int x,int y) {return x<y?x:y;}
 25 
 26 void ins(int x,int y,int f)
 27 {
 28     tt[++len].x=x;tt[len].y=y;tt[len].f=f;
 29     tt[len].next=first[x];first[x]=len;tt[len].o=len+1;
 30     tt[++len].x=y;tt[len].y=x;tt[len].f=0;
 31     tt[len].next=first[y];first[y]=len;tt[len].o=len-1;
 32 }
 33 
 34 int ffind(int x)
 35 {
 36     if(fa[x]!=x) fa[x]=ffind(fa[x]);
 37     return fa[x];
 38 }
 39 
 40 queue<int > q;
 41 bool bfs()
 42 {
 43     while(!q.empty()) q.pop();
 44     memset(dis,-1,sizeof(dis));
 45     q.push(st);dis[st]=0;
 46     while(!q.empty())
 47     {
 48         int x=q.front();q.pop();
 49         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 50         {
 51             int y=t[i].y;
 52             if(dis[y]==-1)
 53             {
 54                 dis[y]=dis[x]+1;
 55                 q.push(y);
 56             }
 57         }
 58     }
 59     if(dis[ed]==-1) return 0;
 60     return 1;
 61 }
 62 
 63 int find_flow(int x,int flow)
 64 {
 65     if(x==ed) return flow;
 66     int now=0;
 67     for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 68     {
 69         int y=t[i].y;
 70         if(dis[y]==dis[x]+1)
 71         {
 72             int a=find_flow(y,mymin(t[i].f,flow-now));
 73             t[i].f-=a;
 74             t[t[i].o].f+=a;
 75             now+=a;
 76                 if(now==flow) break;
 77         }
 78     }
 79     if(now==0) dis[x]=-1;
 80     return now;
 81 }
 82 
 83 int max_flow()
 84 {
 85     int ans=0;
 86     while(bfs()) 
 87         ans+=find_flow(st,INF);
 88     return ans;
 89 }
 90 
 91 bool check(int x)
 92 {
 93     for(int i=1;i<=len;i++) t[i]=tt[i];
 94     for(int i=len-4*n+1;i<=len;i+=2) t[i].f=x;
 95     return max_flow()==n*x;
 96 }
 97 
 98 void finda()
 99 {
100     int l=0,r=n*n;
101     while(l<r)
102     {
103         int mid=(l+r+1)>>1;
104         if(check(mid)) l=mid;
105         else r=mid-1;
106     }
107     printf("%d\n",l);
108 }
109 
110 int main()
111 {
112     int T;
113     scanf("%d",&T);
114     while(T--)
115     {
116         len=0;
117         memset(first,0,sizeof(first));
118         memset(map,0,sizeof(map));
119         scanf("%d%d%d",&n,&m,&k);
120         for(int i=1;i<=m;i++)
121         {
122             int x,y;
123             scanf("%d%d",&x,&y);
124             map[x][y]=1;
125         }
126         for(int i=1;i<=n;i++) fa[i]=i;
127         for(int i=1;i<=k;i++)
128         {
129             int x,y;
130             scanf("%d%d",&x,&y);
131             fa[ffind(x)]=ffind(y);
132         }
133         for(int i=1;i<=n;i++)
134          for(int j=1;j<=n;j++) if(ffind(i)==ffind(j))
135          {
136              for(int k=1;k<=n;k++) if(map[j][k])
137               map[i][k]=1;
138          }
139         for(int i=1;i<=n;i++)
140          for(int j=1;j<=n;j++) if(map[i][j])
141             ins(i,j+n,1);
142         st=2*n+1;ed=st+1;
143         for(int i=1;i<=n;i++) ins(st,i,INF);
144         for(int i=1;i<=n;i++) ins(i+n,ed,INF);
145         finda();
146     }
147     return 0;
148 }
149 
150 [HDU3081]
HDU 3081

 

主要步驟是:一、bfs求dis node

      二、find->儘可能把流量流完ios

      三、max——flow->每次bfs後find找盡增廣路算法

 


 

費用流(是在流量最大的狀況下費用最優)網絡

跟最大流有點不同,就是bfs那部分變成了加權的spfa。ide

模板:函數

運輸問題優化

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<cmath>
  8 using namespace std;
  9 #define Maxn 1010
 10 #define INF 0xfffffff
 11 
 12 struct node
 13 {
 14     int x,y,f,o,c,next;
 15 }t[Maxn*Maxn],tt[Maxn*Maxn];int len;
 16 int first[Maxn];
 17 
 18 int mymin(int x,int y) {return x<y?x:y;}
 19 int mymax(int x,int y) {return x>y?x:y;}
 20 
 21 void ins(int x,int y,int f,int c)
 22 {
 23     t[++len].x=x;t[len].y=y;t[len].f=f;t[len].c=c;
 24     t[len].next=first[x];first[x]=len;t[len].o=len+1;
 25     t[++len].x=y;t[len].y=x;t[len].f=0;t[len].c=-c;
 26     t[len].next=first[y];first[y]=len;t[len].o=len-1;
 27 }
 28 
 29 int st,ed;
 30 queue<int > q;
 31 int dis[Maxn],pre[Maxn],flow[Maxn];
 32 bool inq[Maxn];
 33 bool bfs()
 34 {
 35     while(!q.empty()) q.pop();
 36     memset(dis,63,sizeof(dis));
 37     memset(inq,0,sizeof(inq));
 38     q.push(st);dis[st]=0;flow[st]=INF;inq[st]=1;
 39     while(!q.empty())
 40     {
 41         int x=q.front();
 42         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 43         {
 44             int y=t[i].y;
 45             if(dis[y]>dis[x]+t[i].c)
 46             {
 47                 dis[y]=dis[x]+t[i].c;
 48                 pre[y]=i;
 49                 flow[y]=mymin(flow[x],t[i].f);
 50                 if(!inq[y])
 51                 {
 52                     inq[y]=1;
 53                     q.push(y);
 54                 }
 55             }
 56         }
 57         inq[x]=0;q.pop();
 58     }
 59     if(dis[ed]>=INF-100000) return 0;
 60     return 1;
 61 }
 62 
 63 void output()
 64 {
 65     for(int i=1;i<=len;i+=2)
 66      printf("%d->%d %d %d\n",t[i].x,t[i].y,t[i].f,t[i].c);
 67     printf("\n");
 68 }
 69 
 70 int max_flow()
 71 {
 72     int ans=0,sum=0;
 73     while(bfs())
 74     {
 75         sum+=dis[ed]*flow[ed];
 76         ans+=flow[ed];
 77         int now=ed;
 78         while(now!=st)
 79         {
 80             t[pre[now]].f-=flow[ed];
 81             t[t[pre[now]].o].f+=flow[ed];
 82             now=t[pre[now]].x;
 83         }
 84     }
 85     return sum;
 86 }
 87 
 88 int m,n;
 89 
 90 void init()
 91 {
 92     scanf("%d%d",&m,&n);
 93     st=m+n+1;ed=st+1;
 94     len=0;
 95     memset(first,0,sizeof(first));
 96     for(int i=1;i<=m;i++)
 97     {
 98         int x;
 99         scanf("%d",&x);
100         ins(st,i,x,0);
101     }
102     for(int i=1;i<=n;i++)
103     {
104         int x;
105         scanf("%d",&x);
106         ins(i+m,ed,x,0);
107     }
108     for(int i=1;i<=m;i++)
109      for(int j=1;j<=n;j++)
110      {
111          int x;
112          scanf("%d",&x);
113          ins(i,j+m,INF,x);
114      }
115 }
116 
117 int main()
118 {
119     init();
120     for(int i=1;i<=len;i++) tt[i]=t[i];
121     int ans;
122     ans=max_flow();
123     printf("%d\n",ans);
124     for(int i=1;i<=len;i++) t[i]=tt[i];
125     for(int i=1;i<=len;i++) t[i].c=-t[i].c;
126     ans=max_flow();
127     printf("%d\n",-ans);
128     return 0;
129 }
No. 17 運輸問題

 


 

上下界循環流(原圖無源點匯點)ui

 

增長超級源點st,超級匯點ed。

對於一條邊$x->y (k1<=f<=k2)$

拆邊: 

  

  這時要判斷滿流。【只求了循環流可行解】

 

有費用

  要判斷滿流

 


上下界網絡流(原圖有源點匯點)

只需加一條邊變成循環流

 

一、求最大流:刪掉st與ed的邊,從s到t在殘圖跑一遍最大流。

二、有費用:跑最大費用流

 


 

最大流的應用(標No的是網絡流24題)

一、二分圖匹配,可用最大流作。

【No.1飛行員問題】二分圖匹配

【No.5圓桌問題】二分圖多重匹配

【No.7試題庫問題】二分圖多重匹配

【HDU 3472 混合圖的歐拉回路】

  給你一個同時存在有向邊以及無向邊的混合圖,你須要將全部的無向邊定向,使得最後的有向圖存在歐拉回路。歐拉回路的定義:全部點的入度=出度。

  建模:首先隨便給無向邊定向。而後給全部點計算入度以及出度。若是此時有一個點的入度與出度的差是奇數,則必定不存在解。

  不用考慮原本的有向邊了,按照定向的無向邊建圖。你會知道某個點要修改多少條邊的方向才能成立,因而是一個二分圖的多重匹配問題。

 

 二、公平分配問題(m個任務分給n個處理器,每一個任務只有兩種選擇,求任務最多的處理器任務最少)

【LA 2531】

  二分+最大流判滿流

三、區間k覆蓋問題(數軸上有一些帶權的左閉右開區間,選出權值和最大的區間,使得任意一個數最多被k個區間覆蓋)

  對區間[u,v)加邊u->v(1,w),對相鄰兩點i->i+1 (k,0),可離散化。

·變形

【LA2796】 你有2個房間,有365天,有n我的找你租房,第i我的要從第xi到第yi天要一個房(任意一個),付wi的錢,求怎樣安排收的錢最多

1~365天建一個點,st連1流量爲2費用爲0。

  根據輸入的繼續連邊,好比第i我的要從第xi到第yi天要一個房(任意一個),付wi的錢那麼建一條xi->yi+1流量爲1,費用爲wi的邊。

  最後求最大費用最大流(去負跑最小費用最大流便可)。

四、最多不相交路徑(給一個有向圖,求起點到終點最多幾條不相交路徑)

  【No.最長不減子序列問題】

   拆點,點容爲1。(拆點方法也很經常使用啊

五、最小路徑覆蓋

  【No.4魔術球問題】

  先每一個點做爲一條路徑,可是每一個點其實能夠連一條入邊一條出邊,因而拆點,變成二分圖最大匹配。

六、K取方格數問題。POJ 3422Kaka's Matrix Travels

題目大意:給定一個N*M的矩陣。每次遊戲能夠選擇一條以矩陣左上角爲起點,右下角爲終點的路徑,取走在這條路徑上的全部方格內的權值。如今你有K次機會進行遊戲,問最多能獲得多少的權值。其中每一個點能夠被重複通過,但每一個點上的權值最多隻能被取走一次。

建模:每一個點拆成兩個點i、i',建邊i->i',容量爲1,費用爲-w,同時再建邊i->i',容量爲無窮大,費用爲0,表示每一個點上的權值最多隻能被取走一次且每一個點能被通過屢次。每一個點u向它右邊的點v建邊u'->v,容量爲無窮大,費用爲0。向下同理。最後創建超級源匯S、T,S向矩陣左上角的點建邊,容量爲K,費用爲0,矩陣右下角的點向匯點建邊,容量爲K,費用爲0。最後跑一遍S到T的最小費用最大流,費用的相反數即答案。

七、K路徑覆蓋問題。【HDU】4862 Jump

給定一個N*M的矩陣,矩陣每一個格子中有一個值(0~9),一開始你有活力值爲0,而後你能夠進行最多K次遊戲,每次能夠任選矩陣中的一個點做爲頂點,而後開始遊戲,每次你能夠選擇從這個點跳到它的右邊的點或者下邊的點或者不動。每次跳躍,你將支付兩個點的曼哈頓距離-1的活力值,能量值能夠爲負。若是一次跳躍的起點和終點的格子中的值相同,你的活力值能夠增長這個值大小的值。每一個格子最多隻能夠通過一次且必須通過一次。每次遊戲你能夠跳任意屢次,但不能違反規則。問最後能獲得多少的活力值,若是不能遍歷完全部點則輸出-1。

建模:創建超級源匯S、T,S向全部格子建邊,容量爲1,費用爲0,全部格子拆成兩個,分別爲i,i',i到i'之間建邊,容量爲1,費用爲比全部點的權和還小便可(可設爲-1e5),保證優先遍歷全部點。而後全部點向其右邊的點j建邊(i',j,1,k-1-a),其中k-1爲跳躍長度爲k的花費,當一次跳躍的起點以及終點權值相同時,a等於該權值,不然,a等於0。全部點向其下方的點建邊同上。最後創建超超級源匯S',T',S'向S建邊,容量爲K,費用爲零,T向T'建邊,容量爲K,費用爲0。最後跑最小費用流,若是cost的相反數/100000等於遍歷的N*M(即遍歷的全部點),則答案即(-cost)%100000,不然輸出-1。

這裏須要注意的是,因爲最大流的是否並不必定是最小費用,因此在增廣到增廣路權和爲正時便可退出費用流算法。

 


 

最小割的應用 (最小割模型好多啊。。找找規律)

一、二分圖最大獨立集,可用最小割作。

【No.9方格取數問題】二分圖最大權獨立集

給定一個矩陣,矩陣內每一個方格有一個權值,如今須要你取出一些邊不相鄰的方格內的權值,使得權值和最大。

建模:經典的最小割模型。最小割是最大流的對偶問題,最小割的容量等於最大流的容量。

創建超級源匯S,T。將圖進行黑白染色,S和黑色的方格建邊,容量爲黑色方格權值,白色方格和T建邊,容量爲白色方格權值,黑色方格向相鄰的白色方格建邊,容量爲無窮大。最後跑一遍最大流,全部點的權值和減去最大流的流量即答案。

·變形:

給定一個矩陣,矩陣內每一個方格有一個權值,如今你能夠取出一些方格的權值,若是取走了兩個相鄰的方格內的權值,則須要付出一些代價,你須要使得權值和 - 代價的值最大。

只要把中間的INF變成代價便可。

·變形2:

給定一個矩陣,矩陣內的方格內有兩種屬性(假設第一種屬性爲黑色,第二種爲白色),的權值,每一個方格能夠取走其中一個屬性的權值,能夠取相鄰的數,若是取走的相鄰方格屬於同一屬性,須要花費相應的代價,問怎樣取使得權值和-代價的值最大。

建模:如今咱們依舊將圖黑白染色,方格內屬性和染色相同顏色的和源點建邊,邊權爲該屬性的權值;方格內屬性和染色不一樣顏色的和匯點建邊,邊權爲該屬性的權值。同一方格內的兩種屬性之間建邊,容量爲無窮大,表示只能取其中一種屬性,相鄰方格顏色相同的建邊,容量爲相應的代價(這裏全部邊的方向均從源點指向匯點)。最後跑一遍最大流,全部點權值和減去最大流的流量即答案。

【No.24騎士共存問題】二分圖最大點獨立集

在一個 n*n 個方格的國際象棋棋盤上, 馬(騎士) 能夠攻擊的棋盤方格(1-2矩形)。 棋盤某些方格設置了障礙,騎士不得進入。對於給定的 n*n 個方格的國際象棋棋盤和障礙標誌, 計算棋盤上最多能夠放置多少個騎士,使得它們彼此互不攻擊。

二、最大權閉合子圖

【No.2太空飛行計劃問題】

給定帶全圖G(權值可正可負),求一個權和最大的點集,使得起點在該點集中的任意弧,終點也在該點集中。

假設所有正值都選,負值都不選。

st->正值點,邊權爲點值,負值點->ed 邊權爲點值的相反數。若原圖有邊,則點點相連,權值爲INF,跑最小割。

(簡單割:只割源點匯點的可行割,這個模型的最小割是簡單割哦)

三、最大密度子圖。

給出一個無向圖,找到一個點集,使得起點在該點集中的任意弧,終點也在該點集中,且使得這些點之間的邊數除以點數的值(稱爲子圖的密度)最大。

這個我只會一種沒那麼強可是好理解的方法。

建模一:01分數規劃

E/V>=g  =>  E-g*V>=0

轉化爲最大權閉合子圖。

建模二:如今不會了。。。

四、項目分配問題

先來看一個函數。

 

 

項目分配問題便和這個函數息息相關的,由於用網絡流能夠求解這個函數的最小值。

 

建模:創建超級源匯S、T。S向全部的Xi建邊,容量爲ai,表示若是Xi取1則有ai的代價;全部的Xi向T建邊,容量爲bi,表示若是Xi取0則有bi的代價;而後存在(i,j)關係的Xi向Xj建邊,容量爲Cij,表示若是Xi取1,Xj取0時有Cij的代價。

 

最後跑一遍最小割,割的容量即該函數的最小值,也即取值的代價最小。

 

由於這樣建模後,Xi要麼取1,要麼取0,又因爲最小割的局部最大流全局最小割的特性,求出的最大流即最小割,割掉的邊即Xi的取值,若是割掉了S和Xi之間的邊,則說明Xi取1,不然Xi取0。這裏咱們又用到了網絡流的特性:用流量的流向肯定一些變量的取值。

 

讓咱們來看幾道例題。

 

例1、【POJ】3469 Dual Core CPU

 

該題就是這個函數的基本原型。直接套用便可。

 

例2、【ZOJ】2539 Energy Minimization

 

本題稍做改變,只是將代價變成了絕對值而已,仍舊能夠輕鬆解決。

 

例3、【HDU】4307 Matrix

 

本題略顯複雜,一開始咱們能獲得一個顯而易見的函數:

 

 

而後咱們將這個式子進行一步步的分解,使其接近咱們能求解的函數:

 

 

獲得函數一個這樣的形式之後,很驚訝的能夠發現,等式右端括號裏的部分和以前的f函數的定義驚人的類似!

 

當ai取1的時候,須要割掉代價爲sum{bij}(1 <= j <= N)的S->Xi邊,當ai取0的時候須要割掉代價爲ci的Xi->T邊,當ai取1且aj取0時須要割掉代價爲bij的i->j邊。

 

這個咱們跑一遍最小割即括號中函數的最小值,用bij的總價值減去最小割的值即最大的D。

·變形【BZOJ 3996】

    化一下式子獲得D=∑∑Ai∗Aj∗Bij−∑Ai∗Ci (Ai=0或1)
  跟前面有一點點不一樣,想不到就多加一些點了。
  S→Dot(i,j),流量爲bij
  Dot(i,j)→i 以及 Dot(i,j)→j,流量爲 ∞
  連邊 i→T,流量爲ci
     設最小割爲xx,那麼答案就是 ∑∑Bij−x

 

  但其實跟上面同樣建圖就好,你把全部狀況對應的費用想好就能建圖了。

  就是st->i(ci)  i->ed(Eij+Eji) i->j(Eij+Eji) j->ed(0) j->i(0)

  把邊合併,0邊固然不用建,就應該比上面那種建發快不少了。

五、行列模型

【HDU】4975 A simple Gaussian elimination problem.

題目大意:告訴你每一行的元素和,每一列的元素和,每一個元素的取值範圍。若是無解輸出「So naive!」。若是多解輸出「So young!」。若是有惟一解,輸出「So simple!」。

建模:首先每行i用一個結點ri表示,每列j用一個結點cj表示,創建超級源匯,源點向ri建邊,容量爲行i的元素和。cj向匯點建邊,容量爲列j的元素和。全部行向全部列建邊,容量爲取值上限。若是流量等於全部元素的和而且全部行的元素和等於全部列的元素和,則存在解,不然無解。而後須要判斷是否多解。由於一個子四邊形的四個角上的元素知足一個對角線上的元素均可以減少而且另外一對角線上的元素均可以增大則存在多解。

判斷是否多解這裏有兩種方法。

方法一:先掃描一下全部的邊,(i,j)的反悔邊容量即矩陣內[i][j]的容量假設掃描到了第r行,以vis[i][j]標記r行以前的位置i元素是否能夠減少以及位置j元素是否能夠增大,若是存在則vis[i][j]=1,不然vis[i][j]=0,如今看第r行的位置i以及位置j,若是位置i元素能夠增大,則說明存在多解。不然等判斷完r行的[i][j]以及[j][i]後更新vis[i][j]以及vis[j][i]。若是到最後都沒有符合條件的子四邊形存在則說明有惟一解。這裏咱們能夠加一個優化,判斷的時候若是該行(列)元素所有爲0或者所有爲最大值則能夠跳過,由於即便存在也不會在這一行(列)內選擇,該行(列)內是找不到須要的解的。

方法二:能夠想到,若是選擇一條邊遞歸,而後從遞歸裏出來了,說明沒找到環,那麼走這條邊確定找不到環,之後也不用走了,能夠把這條邊刪了。或者這條邊流量爲0,也能夠刪了。

這樣的話每條邊最多隻進一次,O(m)。參見http://www.cnblogs.com/yuiffy/p/3929369.html

六、最小割的關鍵割邊【ZOJ】2532 Internship

首先要明確關鍵割邊的含義:增長這條邊的容量則網絡的流量即會增長。

建模:首先按照題目要求跑一遍最小割(最大流)。而後在殘餘網絡上進行dfs(即只走有流量的邊),先從源點開始進行dfs,將能到達的全部點都標記爲1,而後從匯點開始再進行一次dfs,將能到達的點都標記爲2。最後判斷全部原圖中的邊(只看正向邊),若是該條邊的弧頭被標記爲1,弧尾被標記爲2,則說明這條邊即關鍵割邊。

七、用INF邊在最小割模型中限制選擇

【BZOJ3144】 三維的圖,每一個x,y選一個高度,每一個高度有一個值v[x][y][h],相鄰的(x,y)選的h的差要小於等於D,使得總的v最小,問最小值。

每一個格子拆出40個點。連同S與T用40種代價串起來。即 p(x,y,z)->p(x,y,z+1)邊權f(x,y,z+1)。而後 p(x,y,z)->p(x’,y’,z-d)邊權inf (x,y)與(x’,y’)相鄰

【BZOJ4663】 

一張關係網,每個人是這張關係網上的一個節點(節點編號爲[0,n-1]),(一條 u->v 的邊意味着信息能夠從u 傳遞到 v)。0 號節點是信息的發出者,n-1 號節點是信息的接受者。
一個點能夠通過屢次,一條邊也能夠通過屢次。一次成功的入侵要知足如下條件:對於任意一種可能的傳遞信息的方式(對應着一條從 0 到 n-1 的路徑),必須通過剛好一次被hack 的邊。一次入侵的代價就是你選擇 hack 掉的邊的代價和。小葉子想要知道,若是你擁有 n+e 這樣超神的智商,而你又想最小化代價,那麼你入侵的代價會是多少呢?

解法:把反向邊弄成INF,源點不能到的點刪掉,就能保證同一條路徑不會割兩條邊了。

八、海陸模型

http://www.cnblogs.com/Konjakmoyu/p/5502241.html

·相似

 

·相似2:

按點的屬性建分屬性圖。LA 5905 Pool construction

題目大意:給定一個N * M的網格型地圖,其中有的地方是坑,有的地方是草地,將草地變成坑須要花費D,將坑變爲草地須要花費F,將坑的邊界包圍起來須要每單位花費B(由於之後要將坑灌水變成水池,爲了防止水溢出,須要圍起來)。其中坑能夠不連續的分佈,可是地圖的最外圍必須是草地(也就是說只能把坑補上)。問要將全部的坑的邊界圍起來須要花費的最小值是多少。

建模:每一個點有兩個屬性,坑、或者是草。

最外圍的坑必須是草,這個咱們預處理解決掉。

而後咱們創建超級源匯S、T。

S向草建邊,容量爲D,表示若是割掉S和草的聯繫,將這棵草變成坑所須要的代價。

坑向T建邊,容量爲F,表示若是割掉坑和T的聯繫,將這個坑變成草所須要的代價。

而後全部相鄰的兩個點之間建無向邊,容量爲B,若是有流量從源點流向匯點,則一定是通過了(草->坑)邊。

最後咱們對最外圍的草建邊S-草,容量爲無窮大,表示這個草必定不會變成坑(絕對不會割掉S-草邊)

如今咱們要作的就是將一些草變成坑(割掉S-草邊),將一些坑變成草(割掉坑-T邊)來使得最後從源點到匯點的流量最小。該最小流量的定義即是最小割。

 


其餘小技巧

一、拆邊(邊權隨流量的單調性)

【LA 5095】費用和流量的平方成正比的最小費用流最大流。容量c均爲整數,每條弧有一個費用係數a,表示該弧流量爲x時費用爲ax^2。

建模:每條邊按照容量大小x拆成x條,容量依次爲a,3a,5a,7a......由於最小費用最大流每次必定是先走最小費用的邊,因此走的必定是先選小的邊,而前k小的邊的權和正好是ak^2,和原題的要求等價。

BZOJ 1449】 給定n支球隊,第i支球隊已經贏了win[i]場,輸了lose[i]場,接下來還有m場比賽,每一個球隊最終的收益爲Cix[i]^2+Diy[i]^2,其中x[i]爲最終的勝場,y[i]爲最終的負場,求最小化收益。

先差分,再拆邊。

注意,輸贏都有貢獻,普通作法不行。直接當成那些比賽全部人都輸,那隻要計算贏的那我的的貢獻。

而後差分:

贏k-1場:c[i]*(win[i]+(k-1))^2+d[i]*(sm[i]+lose[i]-(k-1))^2

贏k場:c[i]=(win[i]+k)^2+d[i]*(sm[i]+lose[i]-k)^2

相減獲得贏第k場:c[i]*(2*win[i]-(2*k-1))-d[i]*(2*(lose[i]+sm[i])-(2*k-1))

這是單調的,因此把本來的貢獻+最大費用流就行了。

2.網絡中邊權有正有負的最小費用流。

建模:若是沒有負費用圈,則只需在增廣到增廣路費用爲正時中止便可。若是存在負費用圈,則應該先用消圈法消去負圈。

三、二分+最大流

【HDU 3081】

n個女生與n個男生配對,每一個女生只能配對某些男生,有些女生相互是朋友,每一個女生也能夠跟她朋友能配對的男生配對。

每次配對,每一個女生都要跟不一樣的男生配對且每一個女生都能配到對。問最多能配對幾輪。(n<=100)

二分+最大流。二分答案,由於有單調性。而後直接最大流了。輸入那裏要用並查集。

四、增長中間點減小邊數(邊合併)

【BZOJ 4205】

如今有一種卡牌遊戲,每張卡牌上有三個屬性值:A,B,C。把卡牌分爲X,Y兩類,分別有n1,n2張。
兩張卡牌可以配對,當且僅當,存在至多一項屬性值使得兩張卡牌該項屬性值互質,且兩張卡牌類別不一樣。
好比一張X類卡牌屬性值分別是225,233,101,一張Y類卡牌屬性值分別爲115,466,99。那麼這兩張牌是能夠配對的,由於只有101和99一組屬性互質。
遊戲的目的是最大化匹配上的卡牌組數,固然每張卡牌只能用一次。

解法:至關於至少兩個屬性不互質,可是直接建圖而後匈牙利或者網絡流都會超時。篩出200之內質數。新建點(2,2,x)等等表示前兩個屬性有2這個約數,鏈接起來,就行了。而後跑網絡流。

 

 


 

一些經典題

【餐巾計劃問題】bzoj1221

http://www.cnblogs.com/Konjakmoyu/p/6030813.html

【BZOJ 3504】

【POJ2699】http://www.cnblogs.com/Konjakmoyu/p/5560165.html

要加入貪心思想

【No.11航空路線問題】

【No.13星際轉移問題】

有時候直接枚舉比二分好,由於能夠跑殘圖。

 


 

先這樣吧,其實還不是很全。。

【我打的最認真的一篇總結了】

 

2017-03-31 14:54:12

 

網絡流24題題表在此:http://www.cnblogs.com/Konjakmoyu/p/6041412.html

上述有部分選自:http://blog.csdn.net/u013368721/article/details/39716401%%%%

相關文章
相關標籤/搜索