标签:
Description
Input
Output
Sample Input
3 4 7 2 0 4 2 6 1 2 40 3 2 70 2 3 90 1 3 120
Sample Output
110
题目大意:有n个棚,有m条路,每个棚紧挨着一些牛,每个棚有一定容量。每条路有一个长度,每条路可以同时跑无数条牛。问要让所有牛有棚住,牛中移动距离的最长路最小能有多小?
分析:与前面的题类似,先跑Floyd,然后都是二分,然后跑最大流,直到满足为止。但是这个题建图有一个很困难的地方。就是拆点及拆点的作用。这里把每个棚拆成两个点,负载为INF,关键在于如果两个点u->v可达且路径长度<=mid,那么此时在u的入点连一条边到v的出点。为什么那么奇葩呢,因为转移的量只能转移一次,如果不拆点流量可能转移多次,那么总路径长度将会大于mid。好好体会一下!
另外不知道为什么二分用 while(low<high){ if(...) low=mid+1;else high=mid} 输出low不行,而用ans记录法(见代码)就可以,求大神解答,叩谢!
上代码
<span style="font-size:18px;">#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int MAXN = 510;
const int MAXM = 330110;
const int inf = 0x3f3f3f3f;
const long long INF = 1e16;
struct Edge
{
int to, cap, next;
};
Edge edge[MAXM];
int level[MAXN];
int head[MAXN];
int cow[MAXN];
int hold[MAXN];
long long dist[MAXN][MAXN];
int src, des, cnt;
void addedge( int from, int to, int cap )
{
edge[cnt].to = to;
edge[cnt].cap = cap;
edge[cnt].next = head[from];
head[from] = cnt++;
edge[cnt].to = from;
edge[cnt].cap = 0;
edge[cnt].next = head[to];
head[to] = cnt++;
}
int bfs( )
{
queue<int> q;
while (!q.empty( ))
q.pop( );
memset( level, -1, sizeof level );
level[src] = 0;
q.push( src );
while (!q.empty( ))
{
int u = q.front( );
q.pop( );
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > 0 && level[v] == -1)
{
level[v] = level[u] + 1;
q.push( v );
}
}
}
return level[des] != -1;
}
int dfs( int u, int f )
{
if (u == des) return f;
int tem;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > 0 && level[v] == level[u] + 1)
{
tem = dfs( v, min( f, edge[i].cap ) );
if (tem > 0)
{
edge[i].cap -= tem;
edge[i ^ 1].cap += tem;
return tem;
}
}
}
level[u] = -1;
return 0;
}
int Dinic( )
{
int ans = 0, tem;
while (bfs( ))
{
while (tem = dfs( src, INF ))
{
ans += tem;
}
}
return ans;
}
int main( )
{
int n, m;
while (cin >> n >> m)
{
int cows = 0;
memset( dist, -1, sizeof dist );
src = 0, des = 501;
for (int i = 1; i <= n; i++)
{
scanf( "%d%d", &cow[i], &hold[i] );
cows += cow[i];
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
dist[i][j] = INF;
}
for (int i = 1; i <= m; i++)
{
int a, b, dis;
scanf( "%d%d%d", &a, &b, &dis );
if (dis < dist[a][b])
dist[a][b] = dist[b][a] = dis;
}
//Floyd
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (dist[i][j] > dist[i][k] + dist[k][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
}
long long low = -1, high = INF - 1;
long long ans = -1;
while (low <= high)
{
long long mid = (low + high) / 2;
memset( head, -1, sizeof head );
cnt = 0;
for (int i = 1; i <= n; i++)
{
addedge( src, i, cow[i] );
addedge( i + 250, des, hold[i] );
addedge( i, i + 250, hold[i] );
}
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
{
if (dist[i][j] <= mid)
{
addedge( i, j + 250, inf );
addedge( j, i + 250, inf );
}
}
}
if (Dinic( ) ==cows)
{
ans = mid;
high = mid-1;
}
else low = mid+1;
}
cout << ans << endl;
}
return 0;
}</span>解题报告 之 POJ2391 Ombrophobic Bovines
标签:
原文地址:http://blog.csdn.net/maxichu/article/details/45154663