poj 3169 Layout 最短路

缘起

日常水题 poj 3169 Layout

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
n头牛在一起进食,但是有一些牛之间的关系较好,进食的距离不能超过一定距离,有一些牛的关系不好,进食的距离
不能小于某个距离,在所有满足这些条件的排序中,求1号牛和N号牛之间的最大距离,如果不存在任何一种排列的话
输出-1,无限大输出-2

【输入】
第一行是 N,ML,MD ,N是牛的数量,ML是关系较好的奶牛对数, MD是关系不好的奶牛对数.
然后是ML行关系好的奶牛,然后是ML条关系不好的奶牛, 每条数据形如 (a,b,c) 表示a和b距离<=(或>=)c

【输出】
满足要求的距离

【样例输入】
4 2 1
1 3 10
2 4 20
2 3 3

【样例输出】
27

【限制】
Time limit 1000 ms
Memory limit 65536 kB

【来源】
USACO 2005 December Gold

令n头牛的位置是 d[i], i=1,…,n(d[i]单调递增), 则按照题意, 对于关系较好的(a,b,c), 我们有

1
d[b]<=d[a]+c

对于关系不好的(a,b,c) ,我们有

1
d[a]+c<=d[b]

现在,我们其实是求所有满足上面ML+MD个条件的d中d[n]-d[1]的最大值.

此题可以巧妙地转换为单源最短路问题. 怎么讲? 你想想我们单源最短路问题中,假设最后 d[1],d[2],…,d[n]是到单源1的最短路. 则我们有

1
2
d[i]+wij>=d[j], for all the arc wij which from i to j,
d[1] = 0 假设1是单源

其实所有满足上述条件的d中,d[i]-d[1]的最大值就是1到i的最短路. 因为d[i]-d[1]不能超过任何一条从1到i的路径长度. 不然就和d[i]是最短路相矛盾了. 注意,是任何一条. 所以 d[i]-d[1]的上界就是最短路. 那么类比于本题就很像了. 我们对于 d[b]<=d[a]+c 的 关系,建立一条长度为c的弧 a–>b . 对于关系 d[a]+c<=d[b], 建立一条长-c的弧

b–>a, 然后我们求1到n的最短路径,就是1到n允许的最大距离了. 注意,有负权边,所以不能使用dijkstra,只能使用spfa. 一旦判定有负环,则输出-1,如果为inf,则输出-2

对于spfa不懂的话,可以参见 【1】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//#include "stdafx.h"

#include <stdio.h>
#include <string.h>
#include <queue>
//#define LOCAL
using namespace std;

int n,ml,md,d[1005], cnt, head[1005], sz[1005]; //sz记录每个节点进队次数, 一旦>=n,则判定有负环
bool isinq[1005];

struct Arc
{
int from,to, nxt, len;
Arc(){}
Arc(int from, int to, int nxt, int len):from(from),to(to),nxt(nxt),len(len){}
}g[200005];

void addArc(int a,int b, int c)
{
g[cnt] = Arc(a,b,head[a], c);
head[a] = cnt++; // 本题是有向图, 不需要双向建边
}

int spfa()
{
queue<int> q;
q.push(1);
while(!q.empty())
{
int front = q.front();
q.pop();
isinq[front] = false;
for (int i = head[front]; ~i; i = g[i].nxt)
{
int to = g[i].to;
if (d[to]>d[front]+g[i].len)
{
d[to] = d[front]+g[i].len;
if (!isinq[to])
{
isinq[to] = true;
if (++sz[to]>=n)
{
return -1; // 判定出现负权环
}
q.push(to);
}
}
}
}
return d[n]==0x3f3f3f3f?-2:d[n];
}

int main()
{
#ifdef LOCAL
freopen("d:\\data.in", "r", stdin);
//freopen("d:\\my.out", "w", stdout);
#endif
scanf("%d%d%d",&n,&ml, &md);
memset(d, 0x3f, sizeof(d));
d[1] = 0;
memset(head, -1, sizeof(head));
while(ml--)
{
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
addArc(a,b,c);
}
while(md--)
{
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
addArc(b,a,-c);
}
printf("%d\n", spfa());
return 0;
}

ac情况

Status Accepted
Time 63ms
Memory 284kB
Length 1312
Lang C++
Submitted 2019-08-23 07:18:59
Shared
RemoteRunId 20790052

参考

【1】https://yfsyfs.github.io/2019/05/27/bellman-ford%E7%AE%97%E6%B3%95%E4%B9%8B%E9%98%9F%E5%88%97%E4%BC%98%E5%8C%96/