图论——最大流

pku2391:

感觉这是一个不错的最大流的题目。

题目大意:有n个农场和m条连接这些农场的路径,牛们走过某条边时都需要一个时间(也就是每条边有一个权值)。牛是很怕下雨的,每个农场有一个牛棚,用来避雨。每个农场两个参数——一个是当前这个农场里牛的个数,另一个是这个农场的牛棚可以容纳的牛的个数。每头牛均可以走到其他农场去避雨,现在暴风雨就要来了,问牛们最少需要走多长时间才能保证每头牛都不会被雨淋到,如果无解则输出-1.

解法:看完题目之后大致有两种思路,一种是贪心——每次寻找最短路,类似于最小费用流每次寻找最小费用路。注意此处和最小费用流是不同的,最小费用流最优化的值是:sigma(f(i,j)*cost(i,j)),而这个题目最优化的值是:让所有增广路径中最长的那一条最短。求解结果几乎扯不上关系。。。一般这种最优化问题,只要解满足单调性,使用二分来逼近是比较好的方式。而且此题中除了与源和汇关联的边,所有的容量可视为INF。所以可以先用floyd预处理一下,然后二分最大增广路径长度,将每个节点拆成两个,建成一个二分图,两端节点分别代表增广路径中除源和汇之外的起点和终点。然后运行最大流判定是否满流就可以了。

贪心的方法就不说了,那种做法是错误的- -!有反例,我实践过了- -!

View Code
#include <iostream>
#include
<cstdio>
#include
<cstring>
usingnamespace std;

typedef
longlong llg;

constint N =210;
constint inf =0x1fffffff;

int n, m, s, t, sum, cows[N], limit[N], queue[N+N], lab[N+N], r[N+N][N+N];
llg dis[N][N];

void floyd()
{
int i, j, k;
for(k =1; k <= n; k++)
for(i =1; i <= n; i++)
if(i!=k && dis[i][k]!=-1)
for(j =1; j <= n; j++)
if(i!=j && j!=k && dis[k][j]!=-1)
{
if(dis[i][j]==-1|| dis[i][j]>dis[i][k]+dis[k][j])
dis[i][j]
= dis[i][k] + dis[k][j];
}
}

bool bfs(int s, int t)
{
int head, tail, i, u;
memset(lab,
-1, sizeof(lab));
lab[s]
= head = tail =0;
queue[
0] = s;
while(head <= tail)
{
u
= queue[head++];
for(i =1; i <= t; i++)
if(r[u][i]>0&& lab[i]==-1)
{
lab[i]
= lab[u] +1;
queue[
++tail] = i;
}
if(lab[t] !=-1) returntrue;
}
returnfalse;
}

int dinicDfs(int delta, int u)
{
int i, sum =0, tmp;
if(u == t) return delta;
else
{
for(i =1; i <= t; i++)
if(lab[i]==lab[u]+1&& r[u][i]>0)
{
tmp
= dinicDfs(min(delta, r[u][i]), i);
sum
+= tmp;
delta
-= tmp;
r[u][i]
-= tmp;
r[i][u]
+= tmp;
}
return sum;
}
}

int maxFlow(int s, int t)
{
int ans =0;
while(bfs(s, t))
ans
+= dinicDfs(inf, s);
return ans;
}

int main()
{
int i, j, x, y, z, tmp;
llg ll, rr, mid, ans;
scanf(
"%d%d", &n, &m);
memset(dis,
-1, sizeof(dis));
sum
=0;
rr
=0;
for(i =1; i <= n; i++)
{
scanf(
"%d%d", cows+i, limit+i);
sum
+= cows[i];
dis[i][i]
=0;
}
for(i =0; i < m; i++)
{
scanf(
"%d%d%d", &x, &y, &z);
if(dis[x][y]==-1|| dis[x][y]>z)
dis[x][y]
= dis[y][x] = z;
rr
+= (llg)z;
}
floyd();
ll
=0;
s
=0;
t
= n+n+1;
ans
=-1;
while(ll <= rr)
{
mid
= (ll+rr) >>1;
memset(r,
0, sizeof(r));
for(i =1; i <= n; i++)
{
r[s][i]
= cows[i];
r[i
+n][t] = limit[i];
}
for(i =1; i <= n; i++)
for(j =1; j <= n; j++)
if(dis[i][j]!=-1&& dis[i][j]<=mid)
r[i][j
+n] = inf;
tmp
= maxFlow(s, t);
if(tmp == sum)
{
ans
= mid;
rr
= mid-1;
}
else ll = mid+1;
}
printf(
"%I64d\n", ans);
return0;
}

  

你可能感兴趣的:(最大流)