题目链接:http://poj.org/problem?id=3169
输入:
4 2 1 1 3 10 2 4 20 2 3 3
输出:
27
题意:第一行N头牛, 编号1 – N排成一列, 然后ML, MD。然后接下来ML行每行AL,BL,CL表示牛AL和牛BL之间的距离不能超过CL, 然后MD行每行AD,BD,CD表示牛AD和牛BD之间距离不能超过CD。求能满足以上条件的1号牛到N号牛的最大距离。无解输出-1, 无限大输出-2。
——挑战程序设计竞赛
差分约束系统,可将其转化为求最短路径的问题。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAX_N = 1010;
const int MAX_ML = 10100;
const int MAX_MD = 10100;
int N, ML, MD;
int AL[MAX_ML], BL[MAX_ML], CL[MAX_ML];
int AD[MAX_MD], BD[MAX_MD], CD[MAX_MD];
int dis[MAX_N];
void solve() {
memset(dis, 0x3f, sizeof(dis));
dis[1] = 0;
int i, j;
//Bellman-ford算法
for(i = 0; i < N; i++) {
for(j = 1; j <= N - 1; j++) { //从j + 1到 j 的边权值为0
dis[j] = min(dis[j], dis[j + 1]);
}
for(j = 1; j <= ML; j++) { //从AL[j]到BL[j]的边权值为CL[j]
dis[BL[j]] = min(dis[BL[j]], dis[AL[j]] + CL[j]);
}
for(j = 1; j <= MD; j++) { //从BD[j]到AD[j]的边权值为-CD[j]
dis[AD[j]] = min(dis[AD[j]], dis[BD[j]] - CD[j]);
}
}
int flag = 0; //判断是否存在负圈
for(j = 1; j <= N - 1; j++) {
if(dis[j] > dis[j + 1]) flag = 1;
}
for(j = 1; j <= ML; j++) {
if(dis[BL[j]] > dis[AL[j]] + CL[j]) flag = 1;
}
for(j = 1; j <= MD; j++) {
if(dis[AD[j]] > dis[BD[j]] - CD[j]) flag = 1;
}
int res = dis[N];
if(flag == 1) res = -1;
//if(d[1] < 0) res = -1; //直接这样写也可以判断负圈,不明白为什么...
else if(res == inf) res = -2;
printf("%d\n", res);
}
int main() {
scanf("%d %d %d", &N, &ML, &MD);
int i;
for(i = 1; i <= ML; i++) {
scanf("%d %d %d", AL + i, BL + i, CL + i);
}
for(i = 1; i <= MD; i++) {
scanf("%d %d %d", AD + i, BD + i, CD + i);
}
solve();
return 0;
}
d
[
B
L
]
−
d
[
A
L
]
≤
D
L