有上下界的、有多組源匯的、網絡流、費用流問題


先默認讀者有基礎的網絡流以及費用流的知識前置                                                                                                                                                                                                                                                                                                                                                   

1.有上下界無源點匯點的可行流問題:

在本文中指:

原圖中沒有任何一個點可以憑空產生流量,亦沒有任何一個點可以憑空消滅流量;

存在邊既有流量上界又有流量下界;

求每條邊流量的一組可行解;

滿足每個點的入流量等於出流量;

由題意可見本題的圖中有環,於是此類問題也被稱作循環流;

這里給出的解法是將本題轉換為一道普通的有上界最大流問題;

修改本題原圖中每條邊的流量下界為0,上界為原上界-原下界;

視為該邊現在已經擁有了等同於該邊流量下界的基礎流量了,

然而,由於每條邊在原圖中的流量下界不同,導致他們現在的基礎流量不同;

於是如果再讓現在圖中每個點出入相等,則表面相等,實則不同;

考慮當現在圖中一條邊i將x的流量匯入點a,實則匯入x+low[i]的流量(low[i]為i的下界),於是應當有額外一條low[i]的邊連入a

考慮當現在圖中一條邊i將x的流量運出點a,實則運出x+low[i]的流量(low[i]為i的下界),於是應當有額外一條low[i]的邊自a連出

由於這些額外的流量在現在圖中看來是憑空產生的,所以所有連入原圖的邊應當自一個額外的源點出發,設為S`

同理,所有連出原圖的邊應當去往一個額外的匯點,設為T`

然后,跑S`到T`的最大流,希望他可以使附加的邊滿流;

若附加邊滿流,則跑出了一組可行流,原圖中每條邊的可行流是他在現在圖中對應邊的流量加流量下界

若不滿流,則說明無論如何,原圖中總會有邊達不到下界,於是原圖不存在可行流;

注意:存在優化——即可以把所有同起點同終點的邊等效為一條流量為加和的邊,從S`到a的邊的流量可以1:1抵消掉從a到T`的流量

2.有上下界無源點匯點的最小費用流問題:

在本文中指:

在上個問題中的圖上加權的費用流問題;

這里給出的解法是直接在上題重構的圖中,給每條邊符合他來歷的權值即可;

由於一定附加邊滿流才有解,於是可以把附加邊貢獻的費用視為0上后單獨算出加到答案中去;

3.有上下界多個有限源匯點的可行流問題:

在本文中指:

在第一個問題的基礎上,有些點必須消滅一定的流量,有些點必須產生一定的流量;

對某些必須產生一定流量x的點,從S`連一條上限為x的附加邊;

對某些必須消滅一定流量x的點,向T`連一條上限為x的附加邊;

跑最大流,期望附加邊滿流;

4.問題3的最小費用流版本:

在問題3上附上費用,直接跑費用流即可

5.有上下界一組無限流量源匯點的可行流問題:

在本文中指:

存在邊既有流量上界又有流量下界;

存在一個源點S可以隨意產生流量,存在一個匯點T可以隨便消滅流量

求每條邊流量的一組可行解;

滿足源匯點之外的每個點入流量等於出流量;

可以看出S的流出等於T的流入;

於是建一條從T到S的流量無限的邊,本題的圖就屬於問題1了;

有趣的是,邊T->S的流量可以視作原圖中S到T的總流量(因為連上此邊后,S,T各自的出入相等)

6.問題5的最小費用流版本:

在問題5上附上費用,直接跑費用流即可

7.問題5的最大流版本:

先跑出問題5的一組可行流;

然而這組可行流並不一定是最大流;

發現一個性質,當我們采用增廣路算法求解最大流時,並不會修改源點到匯點路徑之外的邊的流量大小;

這意味着當我們第一次跑出問題5的一組可行解之后(跑這組可行解,即跑從S`到T`的最大流),

在現在的圖上直接跑S到T的最大流,

就能保證

1不會影響被視作原圖中邊流量下界的邊的流量情況——他們依然是滿流的;

2圖上連的T->S的INF邊的退流過程,等價於有一條S->T的邊在增廣,於是他自動把第一次可行流的答案加入第二次跑出的最大流中;

也就是說,這時跑出來的最大流可以被認為是滿足上下界前提下的最大流;

8.問題7的最小費用流版本:

在問題7上附上費用,直接跑費用流即可

 

題目:

bzojP2502

有上下界多個無限源點的費用流問題,好像保證了合法

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int INF=0x3f3f3f3f;
 6 int n,S,T,ansf,answ;
 7 struct ss{
 8     int next,to,f,v,cp;
 9 }e[30010];
10 int first[210],num;
11 int in[210];
12 int que[100010],dis[210],vis[210],flow[210],pre[210],way[210];
13 void bui_(int ,int ,int ,int );
14 void build(int ,int ,int ,int );
15 bool spfa();
16 void EK();
17 int main()
18 {
19     int i,j,k,l,o;
20     scanf("%d",&n);
21     S=n+1,T=S+1;
22     for(i=1;i<=n;i++)
23         bui_(S,i,INF,1);
24     for(i=1;i<=n;i++){
25         scanf("%d",&k),o=0;
26         for(j=1;j<=k;j++){
27             scanf("%d",&l);
28             bui_(i,l,INF,0);
29             in[l]++;o++;
30         }
31         bui_(i,T,o,0);
32     }
33     for(i=1;i<=n;i++)
34         bui_(S,i,in[i],0);
35     while(spfa())
36         EK();
37     printf("%d\n",ansf);
38     return 0;
39 }
40 void bui_(int f,int t,int fi,int vi){
41     build(f,t,fi,vi),e[num].cp=num+1;
42     build(t,f,0,-vi),e[num].cp=num-1;
43 }
44 void build(int f,int t,int fi,int vi){
45     e[++num].next=first[f];
46     e[num].to=t,e[num].f=fi,e[num].v=vi;
47     first[f]=num;
48 }
49 bool spfa(){
50     int i,h=0,t=1;
51     for(i=1;i<=T;i++)vis[i]=0,dis[i]=0x3f3f3f3f;
52     dis[S]=0,flow[S]=INF,que[t]=S;
53     while(h<t){
54         vis[que[++h]]=0;
55         for(i=first[que[h]];i;i=e[i].next)
56             if(e[i].f&&dis[e[i].to]>dis[que[h]]+e[i].v){
57                 dis[e[i].to]=dis[que[h]]+e[i].v;
58                 pre[e[i].to]=que[h],way[e[i].to]=i;
59                 flow[e[i].to]=min(e[i].f,flow[que[h]]);
60                 if(!vis[e[i].to]){
61                     que[++t]=e[i].to;
62                     vis[que[t]]=1;
63                 }
64             }
65     }
66     return dis[T]!=0x3f3f3f3f;
67 }
68 void EK(){
69     int i;
70     ansf+=(flow[T]*dis[T]);
71     for(i=T;i;i=pre[i])
72         if(way[i])
73             e[way[i]].f-=flow[T],e[e[way[i]].cp].f+=flow[T];
74 }
Code1

bzojP3876

同上,

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int INF=1000000000;
 6 int n,S,T,ansf;
 7 struct ss{
 8     int to,next,f,v,cp;
 9 }e[26010];
10 int first[1000],num;
11 int in[1010];
12 int que[1000010],vis[1010],dis[1010],pre[1010],flow[1010],way[1010];
13 void bui_(int ,int ,int ,int );
14 void build(int ,int ,int ,int );
15 bool spfa();
16 void EK();
17 int main()
18 {
19     int i,j,k,b,t,su;
20     scanf("%d",&n);
21     S=n+1,T=S+1;
22     bui_(S,1,INF,0);
23     for(i=1;i<=n;i++){
24         scanf("%d",&k);
25         for(j=1;j<=k;j++){
26             scanf("%d%d",&b,&t);
27             bui_(i,b,INF,t);
28             bui_(i,T,1,t);
29             in[b]++,su+=t;
30         }
31     }
32     for(i=1;i<=n;i++)
33         if(in[i])
34             bui_(S,i,in[i],0);
35     bui_(S,1,INF,0);
36     while(spfa())
37         EK();
38     printf("%d\n",ansf);
39 }
40 void bui_(int f,int t,int fi,int vi){
41     build(f,t,fi,vi),e[num].cp=num+1;
42     build(t,f,0,-vi),e[num].cp=num-1;
43 }
44 void build(int f,int t,int fi,int vi){
45     e[++num].next=first[f];
46     e[num].to=t,e[num].f=fi,e[num].v=vi;
47     first[f]=num;
48 }
49 bool spfa(){
50     int i,h=0,t=1;
51     memset(vis,0,sizeof(vis));
52     memset(dis,0x3f,sizeof(dis));
53     dis[S]=0,flow[S]=INF,que[t]=S;
54     while(h<t){
55         vis[que[++h]]=0;
56         for(i=first[que[h]];i;i=e[i].next)
57             if(e[i].f&&dis[e[i].to]>dis[que[h]]+e[i].v){
58                 dis[e[i].to]=dis[que[h]]+e[i].v;
59                 pre[e[i].to]=que[h],way[e[i].to]=i;
60                 flow[e[i].to]=min(e[i].f,flow[que[h]]);
61                 if(!vis[e[i].to]){
62                     que[++t]=e[i].to;
63                     vis[que[t]]=1;
64                 }
65             }
66     }
67     return dis[T]!=0x3f3f3f3f;
68 }
69 void EK(){
70     int i;
71     ansf+=(flow[T]*dis[T]);
72     for(i=T;i;i=pre[i])
73         if(way[i])
74             e[way[i]].f-=flow[T],e[e[way[i]].cp].f+=flow[T];
75 }
Code2

bzojP2055

有上下界一個有上限源點的費用流問題,注意拆點限制流量

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int INF=0x3f3f3f3f;
 6 int n,m,S,T,ansf,answ;
 7 struct ss{
 8     int next,to,f,v,cp;
 9 }e[30010];
10 int first[210],num;
11 int que[100010],dis[210],vis[210],flow[210],pre[210],way[210];
12 void bui_(int ,int ,int ,int );
13 void build(int ,int ,int ,int );
14 bool spfa();
15 void EK();
16 int main()
17 {
18     int i,j,k;
19     scanf("%d%d",&n,&m);
20     S=(n<<1)+2,T=S+1;
21     bui_(S,S-1,m,0);
22     for(i=1;i<=n;i++){
23         scanf("%d",&j);
24         bui_(i,T,j,0),bui_(S,i+n,j,0);
25         bui_(S-1,i,INF,0);
26     }
27     for(i=1;i<n;i++)
28         for(j=1;j<=n-i;j++){
29             scanf("%d",&k);
30             if(k!=-1)
31                 bui_(i+n,i+j,INF,k);
32         }
33     while(spfa())
34         EK();
35     printf("%d\n",ansf);
36     return 0;
37 }
38 void bui_(int f,int t,int fi,int vi){
39     build(f,t,fi,vi),e[num].cp=num+1;
40     build(t,f,0,-vi),e[num].cp=num-1;
41 }
42 void build(int f,int t,int fi,int vi){
43     e[++num].next=first[f];
44     e[num].to=t,e[num].f=fi,e[num].v=vi;
45     first[f]=num;
46 }
47 bool spfa(){
48     int i,h=0,t=1;
49     for(i=1;i<=T;i++)vis[i]=0,dis[i]=0x3f3f3f3f;
50     dis[S]=0,flow[S]=INF,que[t]=S;
51     while(h<t){
52         vis[que[++h]]=0;
53         for(i=first[que[h]];i;i=e[i].next)
54             if(e[i].f&&dis[e[i].to]>dis[que[h]]+e[i].v){
55                 dis[e[i].to]=dis[que[h]]+e[i].v;
56                 pre[e[i].to]=que[h],way[e[i].to]=i;
57                 flow[e[i].to]=min(e[i].f,flow[que[h]]);
58                 if(!vis[e[i].to]){
59                     que[++t]=e[i].to;
60                     vis[que[t]]=1;
61                 }
62             }
63     }
64     return dis[T]!=0x3f3f3f3f;
65 }
66 void EK(){
67     int i;
68     ansf+=(flow[T]*dis[T]);
69     for(i=T;i;i=pre[i])
70         if(way[i])
71             e[way[i]].f-=flow[T],e[e[way[i]].cp].f+=flow[T];
72 }
Code3

bzojP3698

有上下界一組源匯點的最大流問題;

  1 #include<cstdio>
  2 #include<cstring>
  3 using namespace std;
  4 const int INF=0x3f3f3f3f;
  5 int n,S,T;
  6 int in[210],out[210];
  7 struct ss{
  8     int next,to,f,cp;
  9 }e[100010];
 10 int first[210],num;
 11 int que[1000010],dep[210],cut[210];
 12 void bui_(int ,int ,int );
 13 void build(int ,int ,int );
 14 bool bfs();
 15 int dfs(int ,int );
 16 int main()
 17 {
 18     int i,j,k,add,ans=0;
 19     double inpu;
 20     scanf("%d",&n);
 21     S=(n<<1)+1,T=S+1;
 22     for(i=1;i<=n;i++)
 23         for(j=1;j<=n;j++){
 24             scanf("%lf",&inpu);
 25             if(i==n&&j==n)continue;
 26             if(i==n){
 27                 if(inpu>(int(inpu)))
 28                     bui_(j+n-1,T-2,1);
 29                 in[T-2]+=int(inpu),out[j+n-1]+=int(inpu);
 30                 continue;
 31             }
 32             if(j==n){
 33                 if(inpu>(int(inpu)))
 34                     bui_(S-2,i,1);
 35                 in[i]+=int(inpu),out[S-2]+=int(inpu);
 36                 continue;
 37             }
 38             if(inpu>(int(inpu)))
 39                 bui_(i,j+n-1,1);
 40             in[j+n-1]+=int(inpu),out[i]+=int(inpu);
 41         }
 42     bui_(T-2,S-2,INF);
 43     for(i=1;i<=T;i++){
 44         if(in[i]>out[i])bui_(S,i,in[i]-out[i]);
 45         if(out[i]>in[i])bui_(i,T,out[i]-in[i]),ans+=out[i]-in[i];
 46     }
 47     while(bfs())
 48         while(add=dfs(S,INF))
 49             ans-=add;
 50     if(ans){
 51         printf("No\n");
 52         return 0;
 53     }
 54     S-=2,T-=2;
 55     while(bfs())
 56         while(add=dfs(S,INF))
 57             ans+=add;
 58     printf("%d\n",ans*3);
 59     return 0;
 60 }
 61 void bui_(int f,int t,int fi){
 62     build(f,t,fi),e[num].cp=num+1;
 63     build(t,f,0),e[num].cp=num-1;
 64 }
 65 void build(int f,int t,int fi){
 66     e[++num].next=first[f];
 67     e[num].to=t,e[num].f=fi;
 68     first[f]=num;
 69 }
 70 bool bfs(){
 71     int i,h=0,t=1;
 72     memset(dep,0,sizeof(dep));
 73     for(i=1;i<=T;i++)cut[i]=first[i];
 74     que[t]=S,dep[S]=1;
 75     while(h<t){
 76         h++;
 77         for(i=first[que[h]];i;i=e[i].next)
 78             if(e[i].f&&!dep[e[i].to]){
 79                 que[++t]=e[i].to;
 80                 dep[que[t]]=dep[que[h]]+1;
 81             }
 82     }
 83     return dep[T];
 84 }
 85 int dfs(int now,int flow){
 86     int i,ret=0;
 87     if(now==T)
 88         return flow;
 89     for(i=cut[now];i;i=e[i].next)
 90         if(e[i].f&&dep[e[i].to]==dep[now]+1){
 91             ret=dfs(e[i].to,flow<e[i].f?flow:e[i].f);
 92             if(ret){
 93                 e[i].f-=ret;
 94                 e[e[i].cp].f+=ret;
 95                 cut[now]=i;
 96                 return ret;
 97             }
 98         }
 99     cut[now]=0;
100     return 0;
101 }
Code4

吐槽一句:

bzoj什么也跑不過,luogu點數26w邊數150w都跑得過

 


免責聲明!

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



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