题目链接:http://poj.org/problem?id=3169
Layout
Description
Some cows like each other and want to be within a certain distance of each other in line. Some really dislike each other and want to be separated by at least a certain distance. A list of ML (1 <= ML <= 10,000) constraints describes which cows like each other and the maximum distance by which they may be separated; a subsequent list of MD constraints (1 <= MD <= 10,000) tells which cows dislike each other and the minimum distance by which they must be separated.
Your job is to compute, if possible, the maximum possible distance between cow 1 and cow N that satisfies the distance constraints.
Input
Lines 2..ML+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at most D (1 <= D <= 1,000,000) apart.
Lines ML+2..ML+MD+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at least D (1 <= D <= 1,000,000) apart.
Output
Sample Input
4 2 1 1 3 10 2 4 20 2 3 3
Sample Output
27
Hint
There are 4 cows. Cows #1 and #3 must be no more than 10 units apart, cows #2 and #4 must be no more than 20 units apart, and cows #2 and #3 dislike each other and must be no fewer than 3 units apart.
The best layout, in terms of coordinates on a number line, is to put cow #1 at 0, cow #2 at 7, cow #3 at 10, and cow #4 at 27.
这题的最短路径算法还是比较抽象的,不容易想出。
记第 i 号牛的位置是 d[i]。按照题目的叙述,牛按顺序排列,且可以站在同一个位置,则有:d[i] <= d[i+1]。
对于关系好的牛而言有:d[A] + D >= d[B]。
对于关系差的牛而言有:d[A] + D <= d[B]。
那么考虑下最短路径的特征,记起点为s,到各个顶点的最短距离为d(v)。因此对于每条权重为w的边e=(v,u),
都有:d[v]+e >= d[u]。等号仅在该边为最短路径上的边时取到。
当对所有的这些约束不等式都满足时,d(v)-d(s)的最大值就是从s到v的最短距离。注意这里是取最大值。
把原问题和最短路特征一比较即可发现,原问题是可以转换成最短路问题求解的。
对于第一种情况,就是d[i+1] + 0 >= d[i]。即从顶点 i+1 向顶点 i 连一条权值为 0 的边。
对于第二种情况,就是d[A] + D >= d[B]。即从顶点 A 向顶点 B 连一条权值为 B 的边。
对于第三种情况,就是d[B] - D >= d[A]。即从顶点 B 向顶点 A 连一条权值为 -D 的边。
所以最终问题转换为了 d[N] - d[1] 的最大值,对应于顶点1到顶点N的距离。
由于图中存在负边。无法使用Dijkstra算法只能使用Bellman-Ford算法。复杂度为O(N(N+ML+MD))。
#include <iostream>
#include <cstdio>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX_N = 1010;
const int MAX_ML = 10010;
const int MAX_MD = 10010;
int n, ml, md;
int d[MAX_N];// 第i头牛的最终位置 也是最短距离
int AL[MAX_ML], BL[MAX_ML], DL[MAX_ML];
int AD[MAX_MD], BD[MAX_MD], DD[MAX_MD];
void solve() {
fill( d, d+n, INF );
d[0] = 0;
for ( int k = 0 ; k < n ; ++ k ) {
// 从i+1到i的权值为0
for ( int i = 0 ; i+1 < n ; ++ i ) {
if ( d[i+1] < INF ) d[i] = min(d[i], d[i+1]);
}
// 从AL到BL的权值为DL
for ( int i = 0 ; i < ml ; ++ i ) {
if ( d[AL[i]-1] < INF ) {
d[BL[i]-1] = min(d[BL[i]-1], d[AL[i]-1] + DL[i]);
}
}
// BD到AD的权值为-DD
for ( int i = 0 ; i < md ; ++ i ) {
if ( d[BD[i]-1] < INF ) {
d[AD[i]-1] = min(d[AD[i]-1], d[BD[i]-1] - DD[i]);
}
}
}
int res = d[n-1];
if ( d[0] < 0 ) {
// 存在负圈则无解
res = -1;
} else if ( res == INF ) {
res = -2;
}
printf( "%d\n", res );
}
int main(int argc, char const *argv[])
{
scanf( "%d%d%d", &n, &ml, &md );
for ( int i = 0 ; i < ml ; ++ i ) {
scanf( "%d%d%d", &AL[i], &BL[i], &DL[i] );
}
for ( int i = 0 ; i < md ; ++ i ) {
scanf( "%d%d%d", &AD[i], &BD[i], &DD[i] );
}
solve();
return 0;
}