ACM/ICPC 之 网络流-拆点构图(POJ2391)

  需要直接到达,因此源点经过三条边后必须要达到汇点,但为了保证网络流的正确性(路径可反悔),因此不可限制层次网络的最高层次为3,最好的方法既是让所有点拆分成两个点,一个点从汇点进入,一个点通向汇点,任意两点的路径则标注为最短路径。

//Dinic算法-拆点构图
//Time:625Ms Memory:2108K
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define MAX 405
#define INF 0x3f3f3f3f
#define LL long long
int n, m;
int s, t;
int cow[MAX], hide[MAX];
LL d[MAX][MAX];
int res[MAX][MAX];
int lev[MAX];
void build_map(LL limit) //拆点构图
{
memset(res, 0, sizeof(res));
for (int i = 1; i <= n; i++)
{
res[s][i] = cow[i];
res[i + n][t] = hide[i];
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (d[i][j] <= limit) res[i][j + n] = INF;
}
bool bfs() //构建层次网络
{
memset(lev, -1, sizeof(lev));
queue<int> q;
q.push(s); lev[s] = 0;
while (!q.empty() && lev[t] == -1) {
int cur = q.front(); q.pop();
for (int i = 1; i <= t; i++)
{
if (lev[i] == -1 && res[cur][i])
{
lev[i] = lev[cur] + 1;
q.push(i);
}
}
}
return lev[t] != -1;
}
int dfs(int x, int sum) //增广并更新
{
if (x == t || sum == 0) return sum;
int src = sum;
for (int i = 1; i <= t; i++)
{
if (lev[i] == lev[x] + 1 && res[x][i])
{
int tmp = dfs(i, min(sum, res[x][i]));
res[x][i] -= tmp;
res[i][x] += tmp;
sum -= tmp;
}
}
return src - sum;
}
int Dinic()
{
int maxFlow = 0;
while (bfs())
maxFlow += dfs(0, INF);
return maxFlow;
}
int main()
{
//freopen("in.txt", "r", stdin);
memset(d, INF, sizeof(d));
scanf("%d%d", &n, &m);
s = 0; t = 2 * n + 1;
int cows = 0; //总牛数
for (int i = 1; i <= n; i++)
{
scanf("%d%d", &cow[i], &hide[i]);
cows += cow[i];
}
for (int i = 1; i <= m; i++)
{
int u, v;
LL w;
scanf("%d%d%lld", &u, &v, &w);
d[u][v] = d[v][u] = min(w, d[u][v]);
}
//Floyd
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
{
d[0][i] = d[i][t] = 0;
if (d[i][k] != d[0][0]) {
for (int j = 1; j <= n; j++)
{
if (i != j) d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
else d[i][j] = 0;
}
}
}
LL l = 0, r = 200LL * 1000000000;
int last;
while (l < r)
{
LL mid = (l + r) / 2;
build_map(mid);
last = Dinic();
last == cows ? r = mid : l = mid + 1;
}
if (r != 200LL * 1000000000)
printf("%lld\n", r);
else printf("-1\n");
return 0;
}
上一篇:关于js中return false、event.preventDefault()和event.stopPropagation()


下一篇:gearman的安装和配置