POJ 2355 Railway Ticket problem

Honour Van發表於2020-12-12

http://poj.org/problem?id=2355

要點:

  1. 插點更新的思路
  2. dp的初態設定要重視
  3. dp的更新順序有時是不影響的。

一維插點求單源最短路(?

  1. 在s與e間進行查詢
  2. 如果中間經停一個車站可以一次到達終點的話,就嘗試用到達這個經停加上最後一站的費用進行更新。

while迴圈尋找可以一步到達本次終點的節點。

    for (int i = s+1; i <= e; i++)
    {
        int j = s;
        while (dist[i] - dist[j] > l[3]) j++;
        for (; j < i; j++) 
            dp[i] = min(dp[j] + cost(dist[i]-dist[j]), dp[i]);
    }

最初以為這裡涉及二維變一維導致的覆蓋順序問題。但把兩段程式碼放在一起說明等價時,發現前一個while迴圈中的l[3]打成了c[3]。低階錯誤

但實際上這步操作可以利用倒序實現:

    for (int i = s+1; i <= e; i++)
    {
        for (int j = i-1; j >= s; j--)
            if (dist[i]-dist[j] > l[3])
                break;
            else 
                dp[i] = min(dp[j] + cost(dist[i]-dist[j]), dp[i]);
    }

另外題中需要注意兩個初態:動態規劃的初始狀態一定要想明白!
距離的初態為0,dp初態為0。

#include <bits/stdc++.h>
using namespace std;

int l[4], c[4];
int cost(int km)
{
    if (km <= l[1])
        return c[1];
    else if (km <= l[2])
        return c[2];
    else if (km <= l[3])
        return c[3];
    else return 1e9+100;
}

int main()
{
#ifdef _LOC_
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif

    cin >> l[1] >> l[2] >> l[3] >> c[1] >> c[2] >> c[3];
    int n, s, e;
    cin >> n >> s >> e;
    if (s > e) swap(s, e);
    int dist[10020];
    int dp[10020]; memset(dp, 0x3f, sizeof dp);
    dp[s] = 0; dist[1] = 0; 									//初態
    for (int i = 2; i <= n; i++)
        cin >> dist[i];
    for (int i = s+1; i <= e; i++)
    {
        for (int j = i-1; j >= s; j--)
            if (dist[i]-dist[j] > l[3])
                break;
            else 
                dp[i] = min(dp[j] + cost(dist[i]-dist[j]), dp[i]);
    }
    cout << dp[e];

#ifdef _LOC_
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}