0w1

UVA 10537 Toll! Revisited ( PFS )

UVa Online Judge
從終點逆推回去更新最小值。具體來說用 Priority First Search,尋找目前還沒用過的擁有最小值的節點來更新它所有可能的前驅點。打印路徑的時候只要反方向( 其實也就是順向 ) 檢查哪些點是可通行的,取其字典序最小慢慢遞進就行了。複雜度不太會估,大概 O( V * V * lg E ) 吧。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, int> pli;
const int MAXN = 60 + 2;
const ll INF = 1LL << 60;

int kase;
int n, m;
vector<int> G[MAXN];
int src, gol, p;

int readPlace(){
    char buf[10]; scanf("%s", buf);
    if( 'A' <= buf[0] && buf[0] <= 'Z' ) return buf[0] - 'A';
    return buf[0] - 'a' + 26;
}
char toPlace(int u){
    if( u < 26 ) return 'A' + u;
    return 'a' + u - 26;
}

int vis[MAXN];
ll need[MAXN];
ll fcost(ll cnt, int v){ // move things toward goal
    if( v >= 26 ) return cnt - 1;
    return cnt - ( cnt + 19 ) / 20; // upper gauss
}
ll bcost(int u){ // minimum requirment for previous
    if( u >= 26 ) return need[ u ] + 1;
    ll res = need[ u ] * 20 / 19;
    while( fcost( res, u ) < need[ u ] ) ++res;
    return res;
}
void pfs(int s){
    memset( vis, 0, sizeof(vis) );
    fill( need, need + MAXN, INF );
    need[ s ] = p;
    priority_queue<pli, vector<pli>, greater<pli> > pq;
    pq.push( pli( need[ s ], s ) );
    vis[ s ] = 1;
    while( !pq.empty() ){
        int u = pq.top().second; pq.pop();
        for(int i = 0; i < G[u].size(); ++i){
            int v = G[u][i];
            if( need[ v ] > bcost( u ) ){
                need[ v ] = bcost( u );
                if( vis[ v ] ) continue;
                vis[ v ] = 1;
                pq.push( pli( need[ v ], v ) );
            }
        }
    }
}

void solve(){
    n = 52; // [ 0, 52 ) <=> [ a, Z ]
    pfs( gol );
    printf("%lld\n", need[ src ]);
    printf("%c", toPlace( src ));
    ll cnt = need[ src ];
    for(int u = src, v; u != gol; u = v){
        v = 100;
        for(int i = 0; i < G[u].size(); ++i){
            int k = G[u][i];
            if( fcost( cnt, k ) >= need[ k ] )
                v = min( v, k ); // lexicographically
        }
        cnt = need[ v ];
        printf("-%c", toPlace( v ));
    }
    puts("");
}

void init(){
    for(int i = 0; i < MAXN; ++i)
        G[i].clear();
}

int main(){
    while( scanf("%d", &n) == 1 && n >= 0 ){
        init();
        for(int i = 0; i < n; ++i){
            int u = readPlace();
            int v = readPlace();
            if( u == v ) continue;
            G[ u ].push_back( v );
            G[ v ].push_back( u );
        }
        scanf("%d", &p);
        src = readPlace();
        gol = readPlace();
        printf("Case %d:\n", ++kase);
        solve();
    }
    return 0;
}