P2740 [USACO4.2]草地排水Drainage Ditches

自為風月馬前卒發表於2017-07-10

題目背景

在農夫約翰的農場上,每逢下雨,貝茜最喜歡的三葉草地就積聚了一潭水。這意味著草地被水淹沒了,並且小草要繼續生長還要花相當長一段時間。因此,農夫約翰修建了一套排水系統來使貝茜的草地免除被大水淹沒的煩惱(不用擔心,雨水會流向附近的一條小溪)。作為一名一流的技師,農夫約翰已經在每條排水溝的一端安上了控制器,這樣他可以控制流入排水溝的水流量。

題目描述

農夫約翰知道每一條排水溝每分鐘可以流過的水量,和排水系統的準確佈局(起點為水潭而終點為小溪的一張網)。需要注意的是,有些時候從一處到另一處不只有一條排水溝。

根據這些資訊,計算從水潭排水到小溪的最大流量。對於給出的每條排水溝,雨水只能沿著一個方向流動,注意可能會出現雨水環形流動的情形。

輸入輸出格式

輸入格式:

 

第1行: 兩個用空格分開的整數N (0 <= N <= 200) 和 M (2 <= M <= 200)。N是農夫John已經挖好的排水溝的數量,M是排水溝交叉點的數量。交點1是水潭,交點M是小溪。

第二行到第N+1行: 每行有三個整數,Si, Ei, 和 Ci。Si 和 Ei (1 <= Si, Ei <= M) 指明排水溝兩端的交點,雨水從Si 流向Ei。Ci (0 <= Ci <= 10,000,000)是這條排水溝的最大容量。

 

輸出格式:

 

輸出一個整數,即排水的最大流量。

 

輸入輸出樣例

輸入樣例#1:
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
輸出樣例#1:
50

說明

題目翻譯來自NOCOW。

USACO Training Section 4.2

 

裸地最大流問題,Dinic演算法

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<queue>
  6 #include<algorithm>
  7 #define lli long long int 
  8 using namespace std;
  9 const int MAXN=300001;
 10 const int maxn=0x7fffff;
 11 void read(int &n)
 12 {
 13     char c='+';int x=0;bool flag=0;
 14     while(c<'0'||c>'9')
 15     {c=getchar();if(c=='-')flag=1;}
 16     while(c>='0'&&c<='9')
 17     {x=x*10+c-48;c=getchar();}
 18     flag==1?n=-x:n=x;
 19 }
 20 struct node
 21 {
 22     int u,v,flow,cap,nxt;
 23 }edge[MAXN];
 24 int head[MAXN];
 25 int num=0;
 26 int n,m,S,T;
 27 int dis[MAXN];
 28 int vis[MAXN];
 29 int cur[MAXN];
 30 void add_edge(int x,int y,int z)
 31 {
 32     edge[num].u=x;
 33     edge[num].v=y;
 34     edge[num].cap=z;
 35     edge[num].flow=0;
 36     edge[num].nxt=head[x];
 37     head[x]=num++;
 38 }
 39 bool bfs(int bg,int ed)
 40 {
 41     memset(dis,-1,sizeof(dis));
 42     queue<int>q;
 43     q.push(bg);
 44     dis[bg]=0;
 45     while(!q.empty())
 46     {
 47         int p=q.front();
 48         q.pop();
 49         for(int i=head[p];i!=-1;i=edge[i].nxt)
 50         {
 51             if(dis[edge[i].v]==-1&&edge[i].cap>edge[i].flow)
 52             {
 53                 vis[edge[i].v]=1;
 54                 dis[edge[i].v]=dis[edge[i].u]+1;
 55                   q.push(edge[i].v);            
 56             }
 57         }
 58     }
 59     if(dis[ed]==-1)
 60         return 0;
 61     else return 1;
 62 }
 63 int dfs(int now,int a)// a:所有弧的最小殘量 
 64 {
 65     if(now==T||a<=0)
 66         return a;
 67         
 68     int flow=0,f;
 69     for(int i=head[now];i!=-1;i=edge[i].nxt)
 70     {
 71         if(dis[now]+1==dis[edge[i].v]&&edge[i].cap-edge[i].flow>0)
 72         {
 73             f=dfs(edge[i].v,min(a,edge[i].cap-edge[i].flow));
 74             edge[i].flow+=f;
 75             edge[i^1].flow-=f;
 76             flow+=f;
 77             a-=f;
 78             if(a<=0)break;
 79         }
 80     }
 81     return flow;
 82 }
 83 void Dinic(int S,int T)
 84 {
 85     int ansflow=0;
 86     for(int i=1;i<=n;i++)
 87             cur[i]=head[i];
 88     while(bfs(S,T))// 求出層級
 89         ansflow+=dfs(S,maxn); 
 90     printf("%d",ansflow);
 91     
 92 }
 93 int main()
 94 {
 95     read(m);read(n);
 96 //    swap(n,m);
 97     S=1;T=n;
 98    // read(S);read(T);
 99     for(int i=1;i<=n;i++)
100         head[i]=-1;
101     for(int i=1;i<=m;i++)
102     {
103         int x,y,z;
104         read(x);read(y);read(z);
105         add_edge(x,y,z);
106         add_edge(y,x,0);
107     }
108     Dinic(S,T);
109     return 0;
110 }