GCJ 2015 Round 1B A. Counter Culture
問題
正整数に対して以下の操作を繰り返し行える。
- 1 加算する
- 文字列と見て前後反転する。leading-zero が生じた時は無視する
整数の $1$ を $N$ にするのに必要な操作の回数の最小値を求めなさい。
方針
移動可能な整数間に有向辺を張ったグラフを構築し、ダイクストラ法で最短路を求める。 しかしこれでは Small しか解けない…
実装
void dijk(Graph const&g, int s, vector<Weight> &dist, vi &prev) {
    int n = g.size();
    dist.assign(n, inf); dist[s] = 0;
    prev.assign(n, -1);
    priority_queue<Edge> q; // "e < f" <=> "e.weight > f.weight"
    q.push(Edge(-2, s, 0));
    while(q.size()) {
        Edge e = q.top();
        q.pop();
        if (prev[e.dst] != -1) continue;
        prev[e.dst] = e.src;
        for(auto & f : g[e.dst]) {
            if (dist[f.dst] > e.weight+f.weight) {
                dist[f.dst] = e.weight+f.weight;
                q.push(Edge(f.src, f.dst, e.weight+f.weight));
            }
        }
    }
}
int my_stoi(string & s){
    int res = 0;
    rep(i,s.size()) res = res*10 + s[i]-'0';
    return res;
}
int rev(int x){
    stringstream ss;
    ss << x;
    string s = ss.str();
    reverse(all(s));
    return my_stoi(s);
}
int solve_small(int N){
    Graph g(N*10);
    for(int i=1;i<N;i++){
        int d1 = i+1;
        int d2 = rev(i);
        g[i].eb(i,d1,1);
        g[i].eb(i,d2,1);
    }
    vi dist, prev;
    dijk(g,1,dist,prev);
    return dist[N];
}