Vijos - 想越獄的小杉(最短路)
背景
這次小杉來到了經典美劇《越獄》的場景裡……
他被抓起來了(-.-幹嘛幻想這麼鬱悶的場景……)。
小杉身為新一代的Scofield,在挖了半個月之後終於挖通牢房裡的地道。
在地道里,無數的管道路線困惑了他。
(若對情節有任何疑問,請觀看原劇)
題目描述
小杉看了看自己的紋身,明白了整個管道網是由N個小房間和若干小房間之間的單向的管道組成的。
小房間編號為不超過N的正整數。
對於某個管道,小杉只能在人品不超過一定程度時通過。
小杉一開始在房間1,現在小杉想知道,每個小房間他最多能夠以人品多少的狀態到達。
注意,小杉的人品在出發以後是不會改變的。
輸入格式
每組測試資料的
第一行有一個正整數N(1<=N<=2000)。
接下來若干行描述管道,每行三個正整數A,B,R(1<=A,B<=N),表示A房間有一條到達B房間的管道,且小杉的人品不超過R時可以通過(注意從B房間不可由此管道到達A房間,即管道是單向的),整個輸入資料以一行0 0 0結束。
特別地,對於30%的資料,有N<=100
輸出格式
對每組測試資料輸出N-1行,分別表示對於2到N號的小房間,小杉最多能夠以人品多少的狀態到達。
樣例輸入
4
1 2 30
1 3 20
2 3 25
3 4 30
2 4 20
0 0 0
樣例輸出
30
25
25
限制
每個測試點1s
提示
對於樣例資料:
小杉最多能夠在人品為30的情況下到達小房間2(1->2)
小杉最多能夠在人品為25的情況下到達小房間3(1->2->3)
小杉最多能夠在人品為25的情況下到達小房間4(1->2->3->4)
解題思路
這道題考察的還是最短路問題,只不過求的是最大的,可以用迪傑斯特拉最短路徑演算法做,只不過要變一下條件。我們知道,求可以通過的最多人品,可以求從1號到n號可以通過的每個房間的最多人品,即求每條路線上子房間的最少人品數(類似於木桶原理),故一部分核心程式碼為:
for (k = 0; k < n; k++)
{
if (map[data][k] < inf)
{
ans = min(dis[data], map[data][k]);
if (!vis[k] && dis[k] < ans)
dis[k] = ans;
}
}
#include <stdio.h>
#define min(a, b) a < b ? a : b
const int inf = 99999999;
int t, map[2010][2010], vis[2010], dis[2010], n, m;
void Dijkstra() {
int data = 0, max, ans, i, j, k;
for (i = 0; i < n; i++) {
dis[i] = map[0][i];
vis[i] = 0;
}
vis[0] = 1;
for (i = 0; i < n; i++) {
max = -inf;
for (j = 0; j < n; j++) {
if (!vis[j] && dis[j] > max) {
max = dis[j];
data = j;
}
}
vis[data] = 1;
for (k = 0; k < n; k++) {
if (map[data][k] < inf) {
ans = min(dis[data], map[data][k]);
if (!vis[k] && dis[k] < ans)
dis[k] = ans;
}
}
}
}
int main() {
int t1, t2, t3;
while (~scanf("%d", &n)) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
map[i][j] = 0;
while (scanf("%d%d%d", &t1, &t2, &t3), t1 + t2 + t3)
map[t1 - 1][t2 - 1] = t3;
Dijkstra();
for (int i = 1; i < n; i++)
printf("%d\n", dis[i]);
}
return 0;
}