UVa10537 The Toll! Revisited [Djikstra/字典序]

Author Avatar
空気浮遊 2018年07月16日
  • 在其它设备中阅读本文章

Sorry 数据小是真的能为所欲为的

Problem

运输货物需要缴纳过路费。进入一个村庄需要缴纳 1 个单位的货物,而进入一个城市每 20 个单位的货物就要上缴 1 个单位。多组询问,对于每组询问,找出一条缴纳过路费最少的路线。无向图中 N 个节点,询问的起点、终点、需要运输的物品数(到达终点时的物品数)不同。
Translated by Awson

虽然可能与原题意有点简略但是也差不多

Solution

什么,反向 Djikstra?
什么,正向 Dijkstra 没法走字典序最小?
NAIVE

二分正向 Dijkstra,再在最短路树上爆搜
10ms 稳

抱歉,数据小是真的能为所欲为的.jpg

至于为什么能最短路呢...
题意满足三角形不等式
边权随到该边的道路变化而变化,因而对求最短路树没有实质性影响
感性理解下(雾)

Code

// Code by ajcxsu
// Problem: toll

#include<bits/stdc++.h>
#define CLR(x) memset(x, 0, sizeof(x))
using namespace std;
typedef long long ll;

const int N=500, M=1e4+10;
int h[N], to[M], nexp[M], p=1;
int typ[N];
inline void ins(int a, int b) { nexp[p]=h[a], h[a]=p, to[p]=b, p++; }

ll dist[N], adis[N];
bool S[N];

void dij(int s, int t, ll w) {
    CLR(S), memset(dist, 0x3f, sizeof(dist));
    dist[s]=0;
    int uu=0;
    ll minn, W;
    while(1) {
        minn=0x3f3f3f3f3f3f3f3fll, uu=0;
        for(int i=1;i<N;i++)
            if(!S[i] && dist[i]<minn) minn=dist[i], uu=i;
        if(!uu) break;
        S[uu]=1;
        for(int u=h[uu];u;u=nexp[u]) {
            W=typ[to[u]]?(w-minn-1)/20+1:1;
            if(!S[to[u]] && dist[to[u]]>dist[uu]+W)
                dist[to[u]]=dist[uu]+W;
        }
    }
}

vector<char> ans;
bool rua(int x, int v, ll w) {
    vector<int> t;
    ll W;
    ans.push_back(x);
    if(x==v) return true;
    for(int u=h[x];u;u=nexp[u]) {
        W=typ[to[u]]?(w-adis[x]-1)/20+1:1;
        if(adis[to[u]]==adis[x]+W) t.push_back(to[u]);
    }
    sort(t.begin(), t.end());
    for(int i=0, len=t.size(); i<len; i++)
        if(rua(t[i], v, w)) return true;
    ans.pop_back();
    return false;
}

int main() {
    ios::sync_with_stdio(false);
    for(int i='A'; i<='Z'; i++) typ[i]=1;
    int m, cnt=0;
    while(cin>>m, m!=-1) {
        char u, v;
        CLR(h), p=1;
        for(int i=1;i<=m;i++)
            cin>>u>>v, ins(u, v), ins(v, u);
        int w;
        cin>>w>>u>>v;
        ll l=w, r=1e15, mid;
        while(r>l) {
            mid=(l+r)>>1ll;
            dij(u, v, mid);
            if(mid-dist[v]>=w) r=mid, memcpy(adis, dist, sizeof(dist));
            else l=mid+1;
        }
        cout<<"Case "<<++cnt<<":"<<endl;
        cout<<r<<endl;
        ans.clear();
        rua(u, v, r);
        for(int i=0, len=ans.size(); i<len; i++) {
            if(i) cout<<'-';
            cout<<ans[i];
        }
        cout<<endl;
    }
    return 0;
}