Drainage Ditches
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 82153 | Accepted: 31914 |
Description
Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
Input
The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.
Output
For each case, output a single integer, the maximum rate at which water may emptied from the pond.
Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output
50
题意:给你一个有向图,每条边都存在他自己的最大流量,1为源点m为汇点,问从源点出发到汇点,在汇点最大可以得到的流量是多少。
题解:最大流模板题,本蒟蒻不才,看了奆佬的博客(
点击打开链接)才勉强明白了这种题怎么做的,一共三种方法,分别为EK(bfs),FF(dfs),Dinic(bfs+dfs),最好都看看才能明白其中的奥妙。本题最大的精华不是怎么找路径而是引入方向边,有兴趣的可有看看奆佬的博客的解释。本题可用邻接表存图也可以用邻接矩阵存图,不过对于其他题邻接表的做法更为保险,所以我一个用的邻接矩阵其他两个用的邻接表。
题解:
一,EK(Edmond—Karp)算法,最原始的方法
我的理解是一直用bfs找增广路并记录它的路线,找到一条后跟新答案,并将这可行弧的正向边减去可行流,反向加上可行流,直到无法找到下增广路为止。
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const double e=exp(1.0);
const double pi=acos(-1);
ll mp[205][205],n,m;
ll EK()
{
ll max_flow=0,flow[205]={0};
flow[1]=inf;
while(1)
{
int dir[205]={0};
dir[1]=0;
queue<int>q;
q.push(1);
while(!q.empty())
{
int now=q.front();
q.pop();
if(now==m)break;
for(int i=1;i<=m;i++)
{
if(i!=1&&mp[now][i]>0&&!dir[i]){
dir[i]=now;
flow[i]=min(mp[now][i],flow[now]);
q.push(i);
}
}
}
if(dir[m]==0)break;
int now=m;
while(now!=1)
{
int next=dir[now];
mp[now][next]+=flow[m];
mp[next][now]-=flow[m];
now=next;
}
max_flow+=(ll)flow[m];
}
return max_flow;
}
int main()
{
int s,e,c;
while(scanf("%lld%lld",&n,&m)!=EOF)
{
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
mp[i][j]=0;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&s,&e,&c);
mp[s][e]+=(ll)c;
}
printf("%lld\n",Ek());
}
return 0;
}
二,FF(Ford-Fulkerson)算法,三种方法中最好理解的一种
和EK算法不一样,FF算法用的是dfs找增广路,和EK比起来,最大的优势是不需要专门用一个数组来记录可行弧的路线,到汇点时,直接带着可行弧的流量回去就可以了,其他的和EK差不多了。
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const double e=exp(1.0);
const double pi=acos(-1);
struct Edge{
int to,cap,rev;//分别记录可以达到的点 最大流量 反向边(为后面的反向标记做准备)
};
int n,m;
bool use[205];
vector<Edge>v[205];
int dfs(int s,int e,int flow)
{
if(s==e)return flow;
use[s]=1;
for(int i=0;i<v[s].size();i++)
{
if(!use[v[s][i].to]&&v[s][i].cap>0)
{
Edge now=v[s][i];
int d=dfs(now.to,m,min(flow,now.cap));
if(d>0){
v[s][i].cap-=d;
v[now.to][now.rev].cap+=d;// 记录反向边 有点巧妙
return d;
}
}
}
return 0;
}
ll FF()
{
ll max_flow=0;
while(1)
{
memset(use,0,sizeof use);
int f=dfs(1,m,inf);
if(f==0)break;
max_flow+=(ll)f;
}
return max_flow;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int s,e,c;
for(int i=1;i<=m;i++)v[i].clear();
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&s,&e,&c);
v[s].push_back((Edge){e,c,v[e].size()});
v[e].push_back((Edge){s,0,v[s].size()-1});//最后那个为标记反向 相当于用vector元素个数来标记
}
printf("%lld\n",FF());
}
return 0;
}
三,
Dinic算法,两种方法的结合优化
Dinic是把EK算法和FF算法rua到一起的算法,对于一些横边很多的图运行速度有大大的提升,其他的道理都差不多,直接看代码
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const double e=exp(1.0);
const double pi=acos(-1);
int n,m,ans;
struct Edge{
int to,cap,rev;
};
vector<Edge>v[205];
int dep[205],iter[105];
bool bfs()
{
queue<int>q;
q.push(1);
memset(dep,0,sizeof dep);
dep[1]=1;//起初没注意要归起点要归1 一直死循环 找了好久的bug
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<v[now].size();i++)
{
if(v[now][i].cap>0&&dep[v[now][i].to]==0)
{
dep[v[now][i].to]=dep[now]+1;
q.push(v[now][i].to);
}
}
}
return dep[m]>0;
}
int dfs(int s,int e,int flow)
{
if(s==e)return flow;
int ff=0;
for(int i=0;i<v[s].size();i++)
{
if(v[s][i].cap>0&&dep[s]==dep[v[s][i].to]-1)
{
int f=dfs(v[s][i].to,e,min(flow-ff,v[s][i].cap));
if(f>0){
v[s][i].cap-=f;
v[v[s][i].to][v[s][i].rev].cap+=f;
ff+=f;
//return f;
}
}
}
if(ff==0)dep[s]=0;
return ff;
}
ll Dinic()
{
ll max_flow=0;
int flow;
while(bfs())
{
//memset(iter,0,sizeof iter);
while(flow=dfs(1,m,inf))
max_flow+=(ll)flow;
}
return max_flow;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int s,e,c;
for(int i=1;i<=m;i++)v[i].clear();
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&s,&e,&c);
v[s].push_back((Edge){e,c,v[e].size()});
v[e].push_back((Edge){s,0,v[s].size()-1});
}
//ans=0;
printf("%lld\n",Dinic());
// printf("%d\n",ans);
}
return 0;
}