- 题目大意
可以给每个点的入边加一个值和出边加一个值,问最小的边权最大是多少。
- 解题思路
根据题目的描述,可以列出一个不等式d(a,b) +x(a)-x(b)>=m,移项可得x(b)-x(a)<=d(a,b)-m正好满足差分约束的形式。所有的边就对应着一个差分约束系统。差分约束有解的充要条件是不存在负环。然后利用SPFA和二分法来查找即可。
- 代码
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N = 1e3;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f;
int n, m;
struct edge {
int v, next, w;
}e[M * 2];
int head[N], cnt;
int d[N];
int inq[N];
int cn[N];
void addedge(int u, int v, int c)
{
e[cnt].w = c;
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
bool SPFA(int s) {
memset(d, INF, sizeof(d));
memset(inq, 0, sizeof(inq));
memset(cn, 0, sizeof(cn));
queue<int> Q;
Q.push(s);
d[s] = 0;
inq[s] = 1;
cn[s]++;
while (Q.size()) {
int u = Q.front();
Q.pop();
inq[u] = 0;
for (int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].v;
int w = e[i].w;
if (d[v] > d[u] + w)
{
d[v] = d[u] + w;
if (!inq[v])
{
Q.push(v);
inq[v] = 1;
if (++cn[v] >= n+1)
return false;
}
}
}
}
return true;
}
bool check(int x)
{
bool vis = true;
for (int i = 0; i <= n; i++)
{
for (int j = head[i]; j != -1; j = e[j].next)
e[j].w -= x;
}
if (!SPFA(0))
vis = false;
for (int i = 0; i <= n; i++)
{
for (int j = head[i]; j != -1; j = e[j].next)
e[j].w += x;
}
return vis;
}
int main()
{
int a, b, c;
while(~scanf("%d%d", &n, &m))
{
int sum = 1;
cnt = 0;
memset(head, -1, sizeof(head));
int l = 1, r = -INF, mid;
for (int i = 0; i < m; i++)
{
scanf("%d%d%d", &a, &b, &c);
addedge(a, b, c);
r = max(r, c);
}
for (int i = 1; i <= n; i++)
addedge(0, i, 0);
if (check(r + 1))
{
printf("Infinite
");
continue;
}
else if (!check(1))
{
printf("No Solution
");
continue;
}
else
{
while (r - l >= 0)
{
mid = (r + l) / 2;
if (check(mid))
{
l = mid + 1;
sum = mid;
}
else
{
r = mid - 1;
}
}
}
printf("%d
", sum);
}
return 0;
}