aytony

求古寻论,散虑逍遥。

0%

题解 洛谷P5960 【模板】差分约束算法

P5960 【模板】差分约束算法 - 洛谷 计算机科学教育新生态

题目大意

给出 \(n\) 个未知数, \(m\) 个约束条件如下。求任意一组在整数意义下满足不等式的解。

\[\left\{    \begin{aligned}        x_{a_1} - x_{b_1} &\leqslant k_1 \\        x_{a_2} - x_{b_2} &\leqslant k_2 \\                          &\vdots \\        x_{a_m} - x_{b_m} &\leqslant k_m \\    \end{aligned}\right.\]

算法选择

差分约束模板。注意从超级源点向每个点连边。关于差分约束,见下。

算法 差分约束 | 散虑の春雨寻风

代码实现

SPFA 期望时间复杂度 \(O(KN)\) ,用时 145ms 。

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
80
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

const int NMAX = 5005;
const int MMAX = 50005;
const int INF = 0x7f7f7f7f;

struct edge
{
int from, to, w;
edge *nxt;
};

// 全局
int n, m;
// 图
edge edges[MMAX], *head[NMAX];
int cnt;
// SPFA
int dis[NMAX], vis[NMAX];
bool inq[NMAX];

inline void addline(int from, int to, int w)
{
edges[cnt] = (edge){from, to, w, head[from]};
head[from] = &edges[cnt++];
}

bool SPFA(int begin)
{
queue<int> que;
dis[begin] = 0;
que.push(begin), inq[begin] = true, vis[begin]++;
while (!que.empty())
{
int fnt = que.front();
que.pop(), inq[fnt] = false;
for (register edge *i = head[fnt]; i; i = i->nxt)
if (dis[i->to] > dis[fnt] + i->w)
{
dis[i->to] = dis[fnt] + i->w;
if (!inq[i->to])
{
que.push(i->to), inq[i->to] = true, vis[i->to]++;
if (vis[i->to] > n)
return false;
}
}
}
return true;
}

int main()
{
scanf("%d%d", &n, &m);
memset(dis, INF, sizeof(dis));
for (register int i = 1, c1, c2, y; i <= m; i++)
{
scanf("%d%d%d", &c1, &c2, &y);
addline(c2, c1, y);
}
for (register int i = 1; i <= n; i++)
addline(0, i, 0);

if (!SPFA(0))
printf("NO");
else
for (register int i = 1; i <= n; i++)
printf("%d ", dis[i]);
putchar(10);

system("pause");
return 0;
}