Drainage Ditches POJ - 1273
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.
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
https://cn.vjudge.net/contest/288484#problem/A
网络流裸题,求1到m的最大流
//ek算法
#include
#include
#include
#include
using namespace std;
long long n,m;
long long pre[5000];// 从 s - t 中的一个可行流中, 节点 i 的前序节点为 Pre[i];
long long vis[5000]; // 标记一个点是否被放进了队列
long long mp[300][300];// 记录图信息
bool bfs(long long s, long long t)
{
queue que;
memset(vis, 0, sizeof(vis));
memset(pre, -1, sizeof(pre));
pre[s] = s;
vis[s] = true;
que.push(s);//把源点放进队列
while(!que.empty())//bfs,找一条s到t的一条路(每条边的权值>0)
{
long long u = que.front();
que.pop();
for(long long i = 1; i <= n; i++)
{
if(mp[u][i] && !vis[i])//把与此点一步可达的点放进队列
{
pre[i] = u;//存入其前驱节点
vis[i] = 1;//标记此点
if(i == t)//已经找到了一条增广路
return true;
que.push(i);
}
}
}
return 0;//已经没有可以走的路
}
long long EK(long long s, long long t)
{
long long ans = 0;
while(bfs(s, t))//如果当前还有增广路
{
long long mi = 0x3f3f3f3f;
for(long long i = t; i != s; i = pre[i])
{
mi = min(mi, mp[pre[i]][i]);//找到此路上的边的最小权值
}
for(long long i = t; i != s; i = pre[i])
{
mp[pre[i]][i] -= mi;//相应的边的权值都减去最小权值
mp[i][pre[i]] += mi;//反向边则加上
}
ans += mi;//结果加上这个最小权值
}
return ans;
}
int main()
{
long long i,aa,bb,cc;
while(scanf("%lld %lld",&m, &n)!=EOF)//边的数目,点的数目(1~n)
{
memset(mp,0,sizeof(mp));
for(i = 0; i < m; i ++)
{
scanf("%lld %lld %lld",&aa, &bb,&cc);
mp[aa][bb] +=cc;
}
printf("%lld\n",EK(1,n));//从1到n的最大流
}
}
//dinic算法
#include
#include
#include
#include
#define MAX 0x3f3f3f3f
using namespace std;
struct Edge
{
int to;
int dis;
int next;
} edges[210000];
int head[10010], cnt;
int n, m, s, t;
void add(int from, int to, int dis)//前向星存边
{
edges[cnt].to = to;
edges[cnt].dis = dis;
edges[cnt].next = head[from];
head[from] = cnt++;
}
int level[10010];
int DFS(int u, int flow)//点,从此点出发所能允许的最大流
{
if (u == t)
return flow;//遍历到终点,就返回此条路上最大流
int flow02 = 0, flow03;//flow记录从此点出发的到达其他点的增光路的总权值,
int ed = head[u], v;
while (ed != -1)//遍历从此点出发的所有边
{
v = edges[ed].to;
if (level[v] == level[u] + 1 && edges[ed].dis > 0)//如果这条边的终点是下一个层次,而且这条边的权值大于0
{
flow03 = DFS(v, min(flow, edges[ed].dis));//min为从此点出发所能允许的最大流量,flow03为这条路上的最大流
flow -= flow03;//从此点出发的流量已经分给了一条边,从此点出发的下一条边所分得的流量将会减少
edges[ed].dis -= flow03;//此边的权值减去,增广路的流
flow02 += flow03;//从此点出发的总流量加上这条路的流量
edges[ed^1].dis += flow03;//反向边的权值加上这个流
if (flow == 0)//从此节点出发的流量已经流完了,下一条边将分不到流量,不能再流了
break;
}
ed = edges[ed].next;
}
if (flow02 == 0)//如果从这个点出发的所有增光路的流都是0,
level[u] = -1;//这个点就废了,不能在往这走了,层次赋值为-1,
return flow02;
}
bool BFS()
{
memset(level, -1, sizeof(level));//先把所有的点的层次都赋值为0
queue que;
level[s] = 0;//源点的层次为0
que.push(s);//源点入队列
int now, ed, nnow;
while (!que.empty())
{
now = que.front();
que.pop();
ed = head[now];//找从此点出发的的第一条边
while (ed != -1)//遍历完此点一步可达的点
{
nnow = edges[ed].to;//边的终点
if (level[nnow] == -1 && edges[ed].dis > 0)//如果找到的点还未被划分层次,且边的权值大于0
{
level[nnow] = level[now] + 1;
que.push(nnow);//将找到的点入队列
}
ed = edges[ed].next;//继续找下一条边
}
}
if (level[t] != -1)
return true;
else//如果bfs没有遍历到汇点(到汇点没有权值大于0的路),说明所有的增广路都找完了
return false;
}
void dinic()
{
int maxflow02 = 0;
while (BFS())//每次用bfs将图重新划分一下层次,直到从源点到汇点没有增广路了
{
maxflow02 += DFS(s, MAX);//结果加上此层次下的dfs遍历结果
}
printf("%d", maxflow02);
}
int main()
{
scanf("%d %d %d %d", &n, &m, &s, &t);
memset(head, -1, sizeof(head));
cnt = 0;
int i, t1, t2, ds;
for (i = 0; i < m; i++)
{
scanf("%d %d %d", &t1, &t2, &ds);
add(t1, t2, ds);
add(t2, t1, 0);//由于正向边,和反向边都是一起建立的,所以两边的编号相差为1,为相邻的偶数和奇数
}
dinic();
return 0;
}
//最小费用最大流
#include
using namespace std;
const int maxn = 120000;
#define inf 0x3f3f3f3f3f3f3f3f
struct node
{
long long to,next,flow,cost;
} edge[maxn];
long long head[maxn],cnt;
long long cost[maxn],last[maxn],flow[maxn],pre[maxn],vis[maxn];
long long max_flow,min_cost;
void add(long long u,long long v,long long flow,long long cost)
{
edge[cnt].to =v;
edge[cnt].next = head[u];
edge[cnt].flow=flow;
edge[cnt].cost=cost;
head[u]=cnt++;
}
bool spfa(long long s,long long t)
{
memset(cost,inf,sizeof(cost));//cost[i]表示s到i的最短路
memset(flow,inf,sizeof(flow));//flow[i]表示s到i的流量
memset(vis,0,sizeof(vis));
queueque;
que.push(s);
vis[s] = 1;
cost[s] = 0;
pre[t]=-1;
while(!que.empty())//spfa求最短路
{
long long x = que.front();
que.pop();
vis[x]=0;
for(long long i = head[x]; i!=-1; i =edge[i].next)
{
long long to = edge[i].to;
if(edge[i].flow>0&&cost[to]>cost[x]+edge[i].cost)//路更短,流量大于0,就增广
{
cost[to] = cost[x]+edge[i].cost;
pre[to] = x;
last[to] = i;//记录这条边
flow[to] = min(flow[x],edge[i].flow);
if(!vis[to])
{
que.push(to);
vis[to] =1;
}
}
}
}
return pre[t]!=-1;
}
void mcmf(long long s,long long t)
{
max_flow = min_cost = 0;
while(spfa(s,t))//每次找一条从源点到汇点最短的流量大于0的路
{
max_flow += flow[t];//这条路的流量就是最后到达汇点的流量
min_cost+=flow[t]*cost[t];//费用就是距离*流量
for(long long i=t; i!=s; i = pre[i])//把这条路上的正向边点的流量减去flow,反向边加上刘
{
edge[last[i]].flow-=flow[t];
edge[last[i]^1].flow+=flow[t];
}
}
}
int main()
{
long long i,j,m,n,s,t,a,b,c,d;
cin>>n>>m>>s>>t;//点的个数(1~n),边的个数,源点,汇点
memset(head,-1,sizeof(head));
for(i = 0; i>a>>b>>c>>d;//起点,终点,流,费用
add(a,b,c,d);
add(b,a,0,-d);
}
mcmf(s,t);
printf("%lld %lld\n",max_flow,min_cost);//最大流,最小费用
return 0;
}