题意:
题目要求求得一个最大的最小权值,任意选择一个点,以这个点为终点的边减去一个数d,以这个点为起点的边江上d,那么对于一个点,可总和与该点的操作为d[a],二分枚举最小的权值x.假设边为a->b,那么对于a->b的边就有x<=w[a,b]+d[a]-d[b],那么就能推出d[b]<=d[a]+w[a,b]-x;
那么把w[a,b]-x当成整体的化形式就很熟悉了,这是一个差数约分系统,只要没有负环就是有解
那么要判断是不是无穷大只要最小权值是原先的最大值即可,判断是不是无解只要原先的最小权值不能得到正环,也就是没有任何操作使得x==最小权值成立
建立超级原点是确保原点与每个点都连接
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 505;
const int INF = 0x3f3f3f3f;
int n, m;
struct edge {
int u,v, w;
int next;
}e[2705+1000];
int head[maxn];
int num;
int d[maxn];
void add(int a, int b, int c) {
e[num].u = a;
e[num].v = b;
e[num].w = c;
e[num].next = head[a];
head[a] = num++;
}
bool bell(int k) {
for(int i=1; i<=n; i++)
d[i] = INF;
d[0] = 0;
for(int q=0; q<n; q++)
for(int i=0; i<num; i++) {
int a = e[i].u, b = e[i].v;
if(d[a] != INF && d[b] > d[a]+e[i].w-k) {
d[b] = d[a] + e[i].w - k;
}
}
for(int i=0; i<num; i++) {
if(d[e[i].u] != INF && d[e[i].v] > d[e[i].u]+e[i].w-k)
return false;
}
return true;
}
int main() {
int a, b, c;
while(scanf("%d%d", &n, &m) != EOF) {
num = 0;
memset(head, -1, sizeof(head));
int l, r = 0;
for(int i=1; i<=n; i++) add(0, i, 0);
for(int i=0; i<m; i++) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
r = max(r, c);
}
l = 1;
if(bell(r)) {
puts("Infinite");
continue;
}
else if(!bell(l)) {
puts("No Solution");
continue;
}
int ans=l++;
while(l<r) {
int mid = (l+r)/2;
if(bell(mid)) {
l = mid+1;
ans = mid;
}
else r = mid;
}
printf("%d\n",ans);
}
return 0;
}