网上的报告基本都是
拆分结点(为什么这么做不是完全明白,囧)
二分查找最大距离,网络流计算最大流与总的牛的头数比较
思路比较清晰,最大流用SAP算法
#include <iostream>
#include <vector>
#include <map>
#include <list>
#include <set>
#include <deque>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <iomanip>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
#include <queue>
using namespace std;
///宏定义
const __int64 INF = 100000000000000;
const int MAXN = 500;
///全局变量 和 函数
int f, p;//顶点数(牛棚数) 和 边数
__int64 len[MAXN][MAXN]; //保存路径中的边的值,即传送时间
__int64 maze[MAXN][MAXN];//残留网络
__int64 ans;//最终答案
int s, t, vnum, total;
struct node
{
int cur, max; //当前的牛的数目 最大容纳的牛的数目
}q[300]; //顶点信息
void Floyd()
{
int i, j, k;
for (k = 1; k <= f; k++)
{
for (i = 1; i <= f; i++)
{
for (j = 1; j <= f; j++)
{
if (len[i][j] > len[i][k] + len[k][j])
{
len[i][j] = len[i][k] + len[k][j];
}
}
}
}
}
//
//SAP 算法
#define CLR(arr, what) memset(arr, what, sizeof(arr))
#define min(a,b) (a < b) ? a : b
int pre[MAXN], cur[MAXN]; //前驱、后继
int gap[MAXN]; //层结点数(用于间隙优化)
int dis[MAXN]; //到汇点的最少弧的数目
int SAP(int s, int t, int n) //源点、汇点、结点数
{
CLR(gap, 0); CLR(cur, 0); CLR(dis, 0);
int u = pre[s] = s, maxflow = 0, v;
__int64 aug = INF;
gap[0] = n;
while(dis[s] < n)
{
bool flag = false;
for(v = cur[u]; v <= n; ++v) //寻找允许弧
{
if(maze[u][v] > 0 && dis[u] == dis[v] + 1)
{
flag = true;
break;
}
}
if(flag) //找到允许弧
{
pre[v] = u;
cur[u] = v;
aug = min(aug, maze[u][v]);
u = v;
if(v == t) //找到完整增广路
{
maxflow += aug;
for(v = t; v != s; v = pre[v]) //更新残留网络
{
maze[pre[v]][v] -= aug; //正向边
maze[v][pre[v]] += aug; //反向边
}
aug = INF, u = s; //重新从源点寻找
}
}
else //找不到允许弧
{
int mindis = n;
for(v = 1; v <= n; ++v) //重新标号
{
if(maze[u][v] && mindis > dis[v])
{
cur[u] = v;
mindis = dis[v];
}
}
if(--gap[dis[u]] == 0) //更新断层 + 判断是否断层(间隙优化)
break;
gap[dis[u] = mindis + 1]++; //更新断层
u = pre[u]; //当前弧优化
}
}
return maxflow;
}
//
void cal()
{
int i, j, k;
__int64 l = 0, r = INF, mid;
while (l < r)
{
mid = (l + r) / 2;
memset(maze, 0, sizeof(maze));
//拆分每一个点
//从超级源点到该点的可用流量为当前顶点的牛的头数
//从顶点到超级汇点的可用流量为当前的最大的容量
//构造网络流图
for (i = 1; i <= f; i++)
{
maze[s][i] = q[i].cur;
maze[i][i + f] = INF;
maze[i + f][t] = q[i].max;
}
//如果该路径可用则构造一条从Aout到Bin的无穷通路
for(i = 1; i <= f; i++)
{
for (j = 1; j <= f; j++)
{
if (i != j && mid >= len[i][j])
{
maze[i][j + f] = INF;
}
}
}
int temp = SAP(s, t, 2 * f + 2);
if (temp == total)
{
ans = mid;
r = mid;
}
else
l = mid + 1;
}
}
__int64 a[MAXN];
int main()
{
///变量定义
int i, j, k;
///操作执行
while (scanf("%d%d", &f, &p) != EOF)
{
//初始化传送时间,即边的值
for (i = 1; i <= f; i++)
{
for (j = 1; j <= f; j++)
{
if (i == j)
len[i][j] = 0;
else
len[i][j] = INF;
}
}
s = 0;//超级源点
t = 2 * f + 1;//超级汇点
total = 0;//所有的牛的头数
//输入每个顶点信息,并统计总的牛的头数
for (i = 1; i <= f; i++)
{
scanf("%d%d", &q[i].cur, &q[i].max);
total += q[i].cur;
}
for (i = 1; i <= p; i++)
{
int u, v;
__int64 d;
scanf("%d%d%I64d", &u, &v, &d);
if (len[u][v] > d)
{
len[u][v] = len[v][u] = d;
}
}
//Floyd算法求解所有源最短路径
Floyd();
ans = -1;
//进行计算
cal();
printf("%I64d\n", ans);
}
///结束
return 0;
}