AtCoder Beginner Contest 051 D - Candidates of No Shortest Paths

解法

Floyd-Warshall algorithmで各頂点間の最小移動距離を計算し, 得られた距離の行列をCとします.
今, 辺端点a, b, 重みをcとする辺eが使われるかどうかを考えます. C_{a b} = cなら, 辺eのみを使う経路がaからbまでの最短経路の集合の中に存在します. C_{a b} < cなら, eを使った時点ですでに移動距離のコストがC_{a b}を超えてしまうことから, eを使ってしまったら, その経路はaからbまでの最短経路とはなりません. よってC_{a b} < cなら任意の頂点間の最短経路において, eが使われることはありません. 仮にeが使われているとすると, その部分をより距離が短い部分に置き換えることができて, 経路の長さが最小であることに反します.
以上より全ての辺についてその端点間の最小距離と辺の重みを比較することで答えを得ることができます.

ソースコード

#include <iostream>
using namespace std;

const int MAX_N = 110;
const int MAX_M = 1010;
const int INF = (1 << 28);

struct Edge {
    int endpoint1;
    int endpoint2;
    int weight;

    Edge() {}
    Edge(int ep1, int ep2, int w)
        : endpoint1(ep1), endpoint2(ep2), weight(w) {}
};

int cost[MAX_N][MAX_N];
Edge edges[MAX_M];

int main() {
    int n, m;
    cin >> n >> m;

    // Floyd-Warshall algorithmのための初期化
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cost[i][j] = (i == j) ? 0 : INF;
        }
    }

    for (int m_i = 0; m_i < m; m_i++) {
        int a, b, c;
        cin >> a >> b >> c;

        a--; b--;
        edges[m_i] = Edge(a, b, c);
        edges[m_i] = Edge(b, a, c);

        cost[a][b] = min(cost[a][b], c);
        cost[b][a] = min(cost[b][a], c);
    }

    // Floyd-Warshall algorithm
    for (int k = 0; k < n; k++) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cost[i][j] = min(cost[i][j], cost[i][k] + cost[k][j]);
            }
        }
    }

    int ans = 0;
    for (int m_i = 0; m_i < m; m_i++) {
        int ep1 = edges[m_i].endpoint1,
            ep2 = edges[m_i].endpoint2,
            w = edges[m_i].weight;
        if (cost[ep1][ep2] < w) {
            ans++;
        }
    }
    cout << ans << endl;

    return 0;
}

感想

試験期間中ですが, 現実逃避するために解きました.