kuangbin 专题四 最短路练习
题目详单见 [kuangbin带你飞]专题1-23。
算法介绍见 最短路 - OI Wiki。
POJ-2387 Til the Cows Come Home
求最短路,方法参见 最短路 - OI Wiki。
1 |
|
1 |
|
POJ-2253 Frogger
极小化极大值,可以用最短路算法,需改更改松弛操作函数,从经典的 f[x][y] = min(f[x][y], f[x][k]+f[k][y])
转为 f[i][j] = min(f[i][j], max(f[i][k], f[k][j]))
。本题也可以用最小生成树算法。需要注意初始值大小,以及比较函数,与下一题相映照。
1 |
|
1 |
|
1 |
|
POJ-1797 Heavy Transportation
同上题,不过是反方向(极大化极小值)。此外,数据量较大不适合用 Floyd。稠密图,更适合用 Prim 而非 Kruskal。
1 |
|
1 |
|
1 |
|
POJ-3268 Silver Cow Party
有向图,多源,单终点,求往返路程最短路的最大值。可以将终点当作源点,正反建图,跑两次最短路算法,求和,最大值为答案。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
using namespace std;
typedef pair<int, int> pii;
const int N = 1001, M = 100001;
int n, m, x, a[M], b[M], t[M];
int h[N], e[M], w[M], ne[M], idx;
int d1[N], d2[N], ans;
bool st[N];
void add(int u, int v, int ww)
{
e[++idx] = v, w[idx] = ww, ne[idx] = h[u], h[u] = idx;
}
void dijstra(int dist[N])
{
memset(st, 0, sizeof st);
priority_queue<pii, vector<pii>, greater<pii> > q;
q.push({0, x});
dist[x] = 0;
while (q.size())
{
int u = q.top().second;
q.pop();
if (st[u])
continue;
st[u] = 1;
for (int i = h[u]; i; i = ne[i])
{
int v = e[i];
if (dist[v] > dist[u] + w[i])
q.push({dist[v] = dist[u] + w[i], v});
}
}
}
int main()
{
scanf("%d%d%d", &n, &m, &x);
for (int i = 0; i < m; ++i)
scanf("%d%d%d", &a[i], &b[i], &t[i]);
memset(h, 0, sizeof h);
for (int i = 0; i < m; ++i)
add(a[i], b[i], t[i]);
memset(d1, 0x3f, sizeof d1);
dijstra(d1);
memset(h, 0, sizeof h);
for (int i = 0; i < m; ++i)
add(b[i], a[i], t[i]);
memset(d2, 0x3f, sizeof d2);
dijstra(d2);
for (int i = 1; i <= n; ++i)
if (i != x && ans < d1[i] + d2[i])
ans = d1[i] + d2[i];
printf("%d\n", ans);
return 0;
}
POJ-1860 Currency Exchange
求正环,将传统 Bellman–Ford 算法改个方向即可。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
using namespace std;
const int N = 101, M = 200;
int n, m, s, tol;
double v;
int e[M][2];
double w[M][2], dist[N];
bool bellmanford()
{
memset(dist, 0, sizeof dist);
dist[s] = v;
for (int i = 1; i <= n; ++i)
{
bool flag = 0;
for (int j = 0; j < tol; ++j)
{
int a = e[j][0], b = e[j][1];
if (dist[b] < (dist[a] - w[j][1]) * w[j][0])
{
dist[b] = (dist[a] - w[j][1]) * w[j][0];
flag = 1;
}
}
if (!flag)
return 0;
}
return 1;
}
int main()
{
scanf("%d%d%d%lf", &n, &m, &s, &v);
for (int i = 0, a, b; i < m; ++i)
{
double r1, c1, r2, c2;
scanf("%d%d%lf%lf%lf%lf", &a, &b, &r1, &c1, &r2, &c2);
e[tol][0] = a, e[tol][1] = b;
w[tol][0] = r1, w[tol][1] = c1;
++tol;
e[tol][0] = b, e[tol][1] = a;
w[tol][0] = r2, w[tol][1] = c2;
++tol;
}
printf(bellmanford() ? "YES\n" : "NO\n");
return 0;
}
POJ-3259 Wormholes
求负环。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
using namespace std;
const int N = 501, M = 5200;
int t, n, m1, m2;
int e[M][2], w[M], dist[N], idx;
bool bellmanford()
{
memset(dist, 0x3f, sizeof dist);
for (int i = 1; i <= n; ++i)
{
int flag = 1;
for (int j = 0; j < idx; ++j)
{
int u = e[j][0], v = e[j][1];
if (dist[v] > dist[u] + w[j])
{
dist[v] = dist[u] + w[j];
flag = 0;
}
}
if (flag) return 0;
}
return 1;
}
int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d%d%d", &n, &m1, &m2);
idx = 0;
for (int i = 0, a, b, c; i < m1; ++i)
{
scanf("%d%d%d", &a, &b, &c);
e[idx][0] = a, e[idx][1] = b, w[idx] = c;
idx++;
e[idx][0] = b, e[idx][1] = a, w[idx] = c;
idx++;
}
for (int i = 0, a, b, c; i < m2; ++i)
{
scanf("%d%d%d", &a, &b, &c);
e[idx][0] = a, e[idx][1] = b, w[idx] = -c;
idx++;
}
printf(bellmanford() ? "YES\n" : "NO\n");
}
return 0;
}
POJ-1502 MPI Maelstrom
单源多目的地最短路,取其中最大值,注意按示例输入建图。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
using namespace std;
const int N = 101;
int n, g[N][N], dist[N];
bool st[N];
struct node
{
int w, u;
bool operator>(const node &a) const { return w > a.w; }
};
void dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<node, vector<node>, greater<node> > q;
q.push({0, 1});
while (!q.empty())
{
int u = q.top().u;
q.pop();
if (st[u])
continue;
st[u] = 1;
for (int v = 1; v <= n; ++v)
if (dist[v] > dist[u] + g[u][v])
q.push({dist[v] = dist[u] + g[u][v], v});
}
}
int main()
{
cin >> n;
memset(g, 0x3d, sizeof g);
for (int i = 2; i <= n; ++i)
for (int j = 1; j < i; ++j)
{
string s;
cin >> s;
if (s[0] == 'x')
continue;
int v = 0;
for (int i = 0; i < s.size(); ++i)
v *= 10, v += s[i] - '0';
g[i][j] = g[j][i] = v;
}
dijkstra();
cout << *max_element(dist + 2, dist + n + 1) << endl;
return 0;
}
POJ-3660 Cow Contest
Floyd 求传递闭包。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
using namespace std;
const int N = 100;
int n, m, a, b, ans;
bool g[N][N];
int main()
{
cin >> n >> m;
while (m--)
{
cin >> a >> b;
g[a - 1][b - 1] = 1;
}
for (int k = 0; k < n; ++k)
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
g[i][j] |= g[i][k] && g[k][j];
for (int i = 0; i < n; ++i)
{
bool flag = 1;
for (int j = 0; j < n; ++j)
if (i != j && !g[i][j] && !g[j][i])
{
flag = 0;
break;
}
if (flag)
++ans;
}
cout << ans << endl;
return 0;
}
POJ-2240 Arbitrage
类似上面的Currency Exchange。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
using namespace std;
const int N = 30, M = N * N;
int t, n, m;
int e[M][2];
double w[M], dist[N];
bool bellmanford()
{
memset(dist, 0, sizeof dist);
dist[0] = 1;
for (int i = 0; i <= n; ++i)
{
bool flag = 0;
for (int j = 0; j < m + n; ++j)
{
int a = e[j][0], b = e[j][1];
if (dist[b] < dist[a] * w[j])
{
dist[b] = dist[a] * w[j];
flag = 1;
}
}
if (!flag)
return 0;
}
return 1;
}
int main()
{
while (cin >> n, n)
{
map<string, int> ccy;
string c1, c2;
for (int i = 0; i < n; ++i)
{
cin >> c1;
ccy[c1] = i;
}
cin >> m;
double r;
for (int i = 0; i < m; ++i)
{
cin >> c1 >> r >> c2;
e[i][0] = ccy[c1], e[i][1] = ccy[c2], w[i] = r;
}
for (int i = m; i < m + n; ++i)
e[i][0] = m, e[i][1] = i - m, w[i] = 1;
bool f = bellmanford();
cout << "Case " << (++t) << ": "
<< (f ? "Yes" : "No") << endl;
}
return 0;
}
POJ-1511 Invitation Cards
单源多目的地最短路,一去一回,求和,回的时候反着建图就行。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
using namespace std;
const int N = 1e6 + 1, M = 2e6;
int t, n, m;
int h1[N], h2[N], e[M], w[M], ne[M], idx;
int d1[N], d2[N];
bool st[N];
void add(int h[], int u, int v, int ww)
{
e[idx] = v, w[idx] = ww, ne[idx] = h[u], h[u] = idx++;
}
struct node
{
int w, u;
bool operator>(const node &a) const { return w > a.w; }
};
void dijkstra(int h[], int d[])
{
priority_queue<node, vector<node>, greater<node> > q;
q.push({0, 1});
d[1] = 0;
memset(st, 0, sizeof st);
while (q.size())
{
int u = q.top().u;
q.pop();
if (st[u])
continue;
st[u] = 1;
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (d[v] > d[u] + w[i])
q.push({d[v] = d[u] + w[i], v});
}
}
}
int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &m);
memset(h1, -1, sizeof h1);
memset(h2, -1, sizeof h2);
memset(d1, 0x3f, sizeof d1);
memset(d2, 0x3f, sizeof d2);
idx = 0;
for (int i = 0, a, b, c; i < m; ++i)
{
scanf("%d%d%d", &a, &b, &c);
add(h1, a, b, c);
add(h2, b, a, c);
}
dijkstra(h1, d1);
dijkstra(h2, d2);
long long ans = 0;
for (int i = 1; i <= n; ++i)
ans += d1[i] + d2[i];
printf("%lld\n", ans);
}
return 0;
}
POJ-3159 Candies
差分约束,注意比较方向。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
using namespace std;
const int N = 30001, M = 150001;
int n, m;
int h[N], e[M], w[M], ne[M], idx;
int d[N];
bool st[N];
void add(int u, int v, int ww)
{
e[++idx] = v, w[idx] = ww, ne[idx] = h[u], h[u] = idx;
}
struct node
{
int w, u;
bool operator>(const node &a) const { return w > a.w; }
};
void dijkstra()
{
priority_queue<node, vector<node>, greater<node> > q;
q.push({0, 1});
memset(d, 0x3f, sizeof d);
memset(st, 0, sizeof st);
d[1] = 0;
while (q.size())
{
int u = q.top().u;
q.pop();
if (st[u])
continue;
st[u] = 1;
for (int i = h[u]; i; i = ne[i])
{
int v = e[i];
if (d[v] > d[u] + w[i])
q.push({d[v] = d[u] + w[i], v});
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0, a, b, c; i < m; ++i)
{
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
dijkstra();
printf("%d\n", d[n]);
return 0;
}
POJ-2502 Subway
求最短路。注意处理好输入,建图 cost
要用时间而非距离以消弭速度差异,此外不能漏掉所有点之间的步行 cost
,最后上最短路算法即可。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
using namespace std;
const int N = 310, INF = 1e9;
struct vertice
{
double x, y;
} vs[N];
int n = 2;
double cost[N][N], d[N];
bool st[N];
struct node
{
double w;
int u;
bool operator>(const node &a) const { return w > a.w; }
};
void dijkstra()
{
for (int i = 2; i <= n; ++i)
d[i] = INF;
d[1] = 0;
priority_queue<node, vector<node>, greater<node> > q;
q.push({0, 1});
while (q.size())
{
int u = q.top().u;
q.pop();
if (st[u])
continue;
st[u] = 1;
for (int v = 1; v <= n; ++v)
if (d[v] > d[u] + cost[u][v])
q.push({d[v] = d[u] + cost[u][v], v});
}
}
double get_dist(vertice &a, vertice &b)
{
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}
int main()
{
double v1 = 10000.0 / 60, v2 = 40000.0 / 60;
scanf("%lf%lf%lf%lf", &vs[1].x, &vs[1].y, &vs[2].x, &vs[2].y);
for (int i = 1; i <= 300; ++i)
for (int j = 1; j <= 300; ++j)
cost[i][j] = i == j ? 0 : INF;
double x, y;
while (~scanf("%lf%lf", &x, &y))
{
vs[++n] = {x, y};
while (scanf("%lf%lf", &x, &y), x != -1)
{
vs[++n] = {x, y};
cost[n][n - 1] = cost[n - 1][n] = min(cost[n][n - 1], get_dist(vs[n], vs[n - 1]) / v2);
}
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
cost[i][j] = min(cost[i][j], get_dist(vs[i], vs[j]) / v1);
dijkstra();
printf("%d\n", (int)(d[2] + 0.5));
return 0;
}
POJ-1062 昂贵的聘礼
等级差的限制是比较难处理的点。可以枚举等级差,再跑最短路。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
using namespace std;
const int N = 101, INF = 0x3f3f3f3f;
int m, n, p, level[N], x, t, v, w[N][N];
int q[N], hh, tt, dist[N], ans = INF;
bool st[N];
int dijkstra(int down, int up)
{
memset(dist, 0x3f, sizeof(dist));
memset(st, 0, sizeof(st));
hh = q[0] = dist[0] = 0, tt = 1;
while (hh != tt)
{
int u = q[hh++];
if (hh == N)
hh = 0;
st[u] = 0;
for (int i = 1; i <= n; ++i)
if (down <= level[i] && level[i] <= up && w[u][i] != INF && dist[i] > dist[u] + w[u][i])
{
dist[i] = dist[u] + w[u][i];
if (!st[i])
{
q[tt++] = i;
if (tt == N)
tt = 0;
st[i] = 1;
}
}
}
return dist[1];
}
int main()
{
scanf("%d%d", &m, &n);
memset(w, 0x3f, sizeof(w));
for (int i = 1; i <= n; ++i)
w[i][i] = 0;
for (int i = 1; i <= n; ++i)
{
scanf("%d%d%d", &p, &level[i], &x);
w[0][i] = p;
while (x--)
{
scanf("%d%d", &t, &v);
w[t][i] = min(w[t][i], v);
}
}
for (int i = level[1] - m; i <= level[1]; ++i)
ans = min(ans, dijkstra(i, i + m));
printf("%d\n", ans);
return 0;
}
POJ-1847 Tram
最短路,数量级小可以直接 Floyd。另外因为路径权值非 0 即 1,可以用 01-BFS。
1 |
|
1 |
|
LightOJ-1074 Extended Traffic
判负环,求最短路。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
using namespace std;
const int N = 201, M = N * N;
int t, n, b[N], m, q;
int e[M][2], w[M], d[N];
bool st[N], flag[N];
void bellmanford()
{
memset(d, 0, sizeof d);
memset(flag, 0, sizeof flag);
memset(st, 0, sizeof st);
st[1] = 1;
for (int k = 1; k < n; ++k)
{
for (int i = 0; i < m; ++i)
{
int u = e[i][0], v = e[i][1];
if (st[u] && (!st[v] || d[v] > d[u] + w[i]))
st[v] = 1, d[v] = d[u] + w[i];
}
}
for (int i = 0; i < m; ++i)
{
int u = e[i][0], v = e[i][1];
if (st[u] && (!st[v] || d[v] > d[u] + w[i]))
flag[v] = 1;
}
}
int main()
{
cin >> t;
for (int _ = 1; _ <= t; ++_)
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> b[i];
cin >> m;
for (int i = 0, u, v; i < m; ++i)
{
cin >> u >> v;
e[i][0] = u, e[i][1] = v, w[i] = pow(b[v] - b[u], 3);
}
bellmanford();
cin >> q;
cout << "Case " << _ << ":" << endl;
while (q--)
{
cin >> m;
if (flag[m] || d[m] < 3)
cout << "?";
else
cout << d[m];
cout << endl;
}
}
return 0;
}
HDU-4725 The Shortest Path in Nya Graph
这一题考验建图。层与层连接,层与层内的点连接。建模:
- 可以虚拟出层点
, - 每一层和它的上一层以及下一层连接,代价为
0
,这样就等于层层相连, - 对于层内的点,建立层点到层内点的单向连接,代价为
c
。(如果是双向连接,将导致原本不连通的点,如层内的两点,连通。)
1 |
|
HDU-3416 Marriage Match IV
1 | // TODO |
HDU-4370 0 or 1
1 | // TODO |
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
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
using namespace std;
const int N = 1001, M = 22000;
int n, ml, md;
int e[M][2], w[M], idx, d[N];
void add(int u, int v, int ww)
{
e[idx][0] = u, e[idx][1] = v, w[idx] = ww, idx++;
}
bool bellmanford()
{
memset(d, 0x3f, sizeof d);
d[1] = 0;
for (int i = 1; i <= n; ++i)
{
int flag = 1;
for (int j = 0; j < idx; ++j)
{
int u = e[j][0], v = e[j][1];
if (d[v] > d[u] + w[j])
{
d[v] = d[u] + w[j];
flag = 0;
}
}
if (flag)
return 0;
}
return 1;
}
int main()
{
scanf("%d%d%d", &n, &ml, &md);
for (int i = 0, a, b, d; i < ml; ++i)
{
scanf("%d%d%d", &a, &b, &d);
if (a > b)
swap(a, b);
add(a, b, d);
}
for (int i = 0, a, b, d; i < md; ++i)
{
scanf("%d%d%d", &a, &b, &d);
if (a > b)
swap(a, b);
add(b, a, -d);
}
for (int i = 1; i < n; ++i)
add(i + 1, i, 0), add(0, i, 0);
add(0, n, 0);
printf("%d\n", bellmanford() ? -1 : (d[n] == 0x3f3f3f3f ? -2 : d[n]));
return 0;
}