CJOJ 2422 [USACO Mar08] 奶牛跑步

奶牛跑步

Description

Bessie準備用從牛棚跑到池塘的方法來鍛鍊. 但是因爲她懶,她只准備沿着下坡的路跑到池塘,然後走回牛棚.

Bessie也不想跑得太遠,所以她想走最短的路經. 農場上一共有M(1<=M<=10,000)條路,每條路連接兩個用1..N(1<=N<=1000)標號的地點. 更方便的是,如果X>Y,則地點X的高度大於地點Y的高度. 地點N是Bessie的牛棚;地點1是池塘.

很快, Bessie厭倦了一直走同一條路.所以她想走不同的路,更明確地講,她想找出K(1<=K<=100)條不同的路經.爲了避免過度勞累,她想使這K條路徑爲最短的K條路徑.

請幫助Bessie找出這K條最短路經的長度.你的程序需要讀入農場的地圖, 一些從Xi到Yi的路徑和它們的長度(Xi,Yi,Di).
所有(Xi,Yi,Di) 滿足( 1<=Yi<Xi; Yi<Xi<=N, 1<=Di<=1,000,000 ).

Input

第1行: 3個數: N,M,K
第2..M+1行: 第 i+1行包含3個數 Xi,Yi,Di, 表示一條下坡的路.

Output

第1..K行: 第i行包含第i最短路徑的長度,或−1如果這樣的路徑不存在.如果多條路徑有同樣的長度,請注意將這些長度逐一列出.

Sample Input

5 8 7
5 4 1
5 3 1
5 2 1
5 1 1
4 3 4
3 1 1
3 2 1
2 1 1

Sample Output

1
2
2
3
6
7
-1

Hint

【樣例解釋】
路徑分別爲(5−1),(5−3−1),(5−2−1),(5−3−2−1),(5−4−3−1),(5−4−3−2−1)

Source

動態規劃, 圖論, A*搜索, k短路

Solution

這道題的標程是A*搜索,然而在網上看到了一個跑的飛快的神奇的遞推,於是妥妥的放棄了A*……

對與插入的每一個點(0號~n - 1號)我們可以記錄一個數組h[i][j],表示i號點到n - 1號點的第j小路的長度,那麼最後答案存於h[0][i]中,遞推方程顯然有: 

for (int i = 0; i < k; ++i)//更新第i小的邊
    if (h[x][t1] + d < h[y][t2]) temp[i] = h[x][t1++] + d;//用其父邊更新最短距離(先到父親再從父親去n - 1)
    else temp[i] = h[y][t2++];//用自己更新(直接從自己去n - 1)
for (int i = 0; i < k; ++i) h[y][i] = temp[i];//記錄第i小路徑

對於初始化,除了從n - 1到n - 1的第1小邊爲0外,其他值都初始化爲最大值(即不存在)

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define LL long long
using namespace std;

inline int gi() {
  char cj = getchar();
  int ans = 0, f = 1;
  while (cj < '0' || cj > '9') {
    if (cj == '-') f = -1;cj = getchar();
  }
  while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar();
  return f * ans;
}

struct node {
  int to, nxt, w;
} e[10010];
int n, m, k, a, b, c, head[1010], cnt, h[1010][110], temp[110];

inline void add(int a, int b, int c) {
  e[++cnt].nxt = head[a], e[cnt].to = b, e[cnt].w = c, head[a] = cnt;
}

inline void update(int x, int y, int d) {
  int t1 = 0, t2 = 0;
  for (int i = 0; i < k; ++i)
    if (h[x][t1] + d < h[y][t2]) temp[i] = h[x][t1++] + d;
    else temp[i] = h[y][t2++];
  for (int i = 0; i < k; ++i) h[y][i] = temp[i];
}

int main() {
  freopen("cowjog.in", "r", stdin);
  freopen("cowjog.out", "w", stdout);
  n = gi(), m = gi(), k = gi();
  for (int i = 0; i < m; ++i) {
    a = gi(), b = gi(), c = gi();
    add(a - 1, b - 1, c);
  }
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < k; ++j)
      h[i][j] = 1e9; h[n - 1][0] = 0;
  for (int i = n - 1; i >= 0; --i)
    for (int j = head[i]; j; j = e[j].nxt)
      update(i, e[j].to, e[j].w);
  for (int i = 0; i < k; ++i)
    printf("%d\n", h[0][i] == 1e9 ? -1 : h[0][i]);
  return 0;
}

Summary

考試的時候完全不會寫(之前沒有練過A*搜索),就直接輸出-1,果然沒有一個這種點……
注意遞推的時候每使用一次h[i][t1]或h[i][t2]都要將t1++或t2++,因爲每個大小的值不能重複


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章