差分约束相关概念:
假设:
x1 - x2 <= k1
x2 - x3 <= k2
x1 - x3 <= k3
==>整理得
x1 - x3 <= k1 + k2
x1 - x3 <= k3
x1和x3的最大差值就是min(k1 + k2, k3)
转化为图
其实就是x1到x3的最短距离。
POJ-3169
可得:
d[AL] + DL >= d[BL]
d[BD] - DD >= d[AD]
因为可能存在负环所以用Bellman-Ford。
若存在负环,输出-1
距离可以任意大输出-2
否则输出距离
Bellman-Ford代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000 + 5, M = 20000 + 5, inf = 0x3f3f3f3f;
struct edge{
int u, v, w;
}e[M];
int d[N], n, ml, md, a, b, dis;
void Bellman_Ford() {
memset(d, 0x3f, sizeof(d));
d[1] = 0;
int flag = 0;
for(int i = 1; i <= n; i++) {
bool update = false;
for(int j = 1; j <= ml + md; j++) {
if(d[e[j].u] != inf && d[e[j].u] + e[j].w < d[e[j].v]) {
d[e[j].v] = d[e[j].u] + e[j].w;
update = true;
}
}
if(!update) break;
if(i == n) flag = 1;
}
if(flag) printf("-1\n");
else if(d[n] == inf) printf("-2\n");
else printf("%d\n", d[n]);
}
int main() {
while(scanf("%d%d%d", &n, &ml, &md) != EOF) {
for(int i = 1; i <= ml + md; i++) {
scanf("%d%d%d", &a, &b, &dis);
if(i <= ml) {
e[i].u = a;
e[i].v = b;
e[i].w = dis;
}
else {
e[i].u = b;
e[i].v = a;
e[i].w = -dis;
}
}
Bellman_Ford();
}
return 0;
}
SPFA代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1000 + 5, M = 20000 + 5, inf = 0x3f3f3f3f;
struct edge{
int next, v, w;
}e[M];
int d[N], n, ml, md, a, b, dis, in[N], head[N], len;
bool vis[N];
struct node{
int v, d;
node(int v, int d): v(v), d(d) {
}
};
void add(int u, int v, int w) {
e[len].v = v;
e[len].w = w;
e[len].next = head[u];
head[u] = len++;
}
void spfa() {
memset(d, 0x3f, sizeof(d));
memset(in, 0, sizeof(in));
memset(vis, false, sizeof(vis));
d[1] = 0;
queue<node> q;
q.push(node(1, 0));
int flag = 0;
while(!q.empty()) {
int u = q.front().v;
in[u]++;
if(in[u] > n) {//存在负环
flag = 1;
break;
}
q.pop();
vis[u] = false;
for(int j = head[u]; j; j = e[j].next) {
int v = e[j].v;
int w = e[j].w;
if(d[v] > d[u] + w) {
d[v] = d[u] + w;
if(!vis[v]) {
q.push(node(v, d[v]));
in[v]++;
vis[v] = true;
}
}
}
}
if(flag) printf("-1\n");
else if(d[n] == inf) printf("-2\n");
else printf("%d\n", d[n]);
}
int main() {
while(scanf("%d%d%d", &n, &ml, &md) != EOF) {
len = 1;
memset(head, 0, sizeof(head));
for(int i = 1; i <= ml + md; i++) {
scanf("%d%d%d", &a, &b, &dis);
if(i <= ml) {
add(a, b, dis);
}
else {
add(b, a, -dis);
}
}
spfa();
}
return 0;
}