SRM624D1Med DrivingPlans

適当に実装したらアホみたいにハマった

問題概要(原文)

$N$ 頂点の連結グラフが与えられる.非負整数の重みつきの辺があるときに,頂点 $1$ から頂点 $N$ への最短経路は何通りあるか? 無限通りあるときは $-1$ を返せ.

考察

無限になる場合は最短経路上の頂点から重みが $0$ の辺が生えている場合である. 頂点 $1$ からの最短経路とその通り数,頂点 $N-1$ からの最短経路とその通り数を計算する.

最短経路上の頂点であって,重みが $0$ の辺と接続しているものがあるかどうか判定する.

ソースコード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Debug = System.Diagnostics.Debug;
using StringBuilder = System.Text.StringBuilder;
public class DrivingPlans
{
    public int count(int N, int[] A, int[] B, int[] C)
    {
        var G = Enumerate(N, x => new List<KeyValuePair<int, long>>());
        for (int i = 0; i < A.Length; i++)
        {
            A[i]--; B[i]--;
            G[A[i]].Add(new KeyValuePair<int, long>(B[i], C[i]));
            G[B[i]].Add(new KeyValuePair<int, long>(A[i], C[i]));
        }
        var dist = Enumerate(2, x => new long[N]);
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < N; j++)
                dist[i][j] = 1000000000000;
        var src = new int[] { 0, N - 1 };
        var pat = Enumerate(2, x => new int[N]);
        for (int k = 0; k < 2; k++)
        {
            dist[k][src[k]] = 0;
            pat[k][src[k]] = 1;
            var pq = new BinaryHeapPriorityQueue<KeyValuePair<int, long>>((l, r) => l.Value.CompareTo(r.Value));
            pq.Enqueue(new KeyValuePair<int, long>(src[k], 0));
            while (pq.Any())
            {
                var p = pq.Dequeue();
                var u = p.Key;
                var v = p.Value;
                if (v > dist[k][u]) continue;
                foreach (var e in G[u])
                {
                    var to = e.Key;
                    var nc = v + e.Value;
                    if (nc < dist[k][to])
                    {
                        dist[k][to] = nc;
                        pat[k][to] = pat[k][u];
                        pq.Enqueue(new KeyValuePair<int, long>(to, nc));
                    }
                    else if (nc == dist[k][to])
                        pat[k][to] = (pat[k][to] + pat[k][u]) % 1000000009;
                }
            }

        }
        for (int i = 0; i < N; i++)
        {
            if (dist[0][N - 1] != dist[0][i] + dist[1][i]) continue;
            foreach (var e in G[i]) if (e.Value == 0) return -1;
        }

        return pat[0][N - 1];
    }

    static public T[] Enumerate<T>(int n, Func<int, T> f) { var a = new T[n]; for (int i = 0; i < n; ++i) a[i] = f(i); return a; }
}
#region PriorityQueue by BinaryHeap
public class BinaryHeapPriorityQueue<T>
{
    private readonly List<T> heap;
    private readonly Comparison<T> compare;
    private int size;
    public BinaryHeapPriorityQueue() : this(Comparer<T>.Default) { }
    public BinaryHeapPriorityQueue(IComparer<T> comparer) : this(16, comparer.Compare) { }
    public BinaryHeapPriorityQueue(Comparison<T> comparison) : this(16, comparison) { }
    public BinaryHeapPriorityQueue(int capacity, Comparison<T> comparison)
    {
        this.heap = new List<T>(capacity);
        this.compare = comparison;
    }
    public void Enqueue(T item)
    {

        this.heap.Add(item);
        var i = size++;
        while (i > 0)
        {
            var p = (i - 1) >> 1;
            if (compare(this.heap[p], item) <= 0)
                break;
            this.heap[i] = heap[p];
            i = p;
        }
        this.heap[i] = item;

    }
    public T Dequeue()
    {
        var ret = this.heap[0];
        var x = this.heap[--size];
        var i = 0;
        while ((i << 1) + 1 < size)
        {
            var a = (i << 1) + 1;
            var b = (i << 1) + 2;
            if (b < size && compare(heap[b], heap[a]) < 0) a = b;
            if (compare(heap[a], x) >= 0)
                break;
            heap[i] = heap[a];
            i = a;
        }
        heap[i] = x;
        heap.RemoveAt(size);
        return ret;

    }
    public T Peek() { return heap[0]; }
    public int Count { get { return size; } }
    public bool Any() { return size > 0; }
}
#endregion

コメント

  • 本当に面倒なだけ