ドイツ大学院生日記

問題を解いた際に自分の復習用として使ってます

ABC051 D問題 Candidates of No Shortest Paths

問題

abc051.contest.atcoder.jp

解説

まずNが少ないのでワーシャルフロイドを使いそうだなと考えられ、実際に使用します。
まず頂点間の最小距離を求めておきます。 そしてある辺が最小距離のパスに使われているかどうかは以下の式を満たしているs, tが存在するかで判断します。

dist(s, t) = dist(s, i) + edge(i, j) + dist(j, t)

この式を満たしているs, tを2重ループを使って探索して一つでも存在すれば最短距離のパスの中に使われていることになります。

コード

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;

const int inf = 1e9;
const int mod = 1e9+7;

struct edge {
    int from, to, cost;
};

typedef pair<int, int> P;
typedef vector<vector<edge> > G;

G graph;
int n, m;

int d[105][105];
bool used[105][105];
vector<edge> dist;

void warshall_floyd(){
    for(int k=0; k<n; k++){
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                if(d[i][j] > d[i][k] + d[k][j]){
                    d[i][j] = d[i][k] + d[k][j];
                }
            }
        }
    }
}

int main(void){
    cin >> n >> m;
    graph = G(n);

    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            if(i == j){
                d[i][j] = 0;
            }else{
                d[i][j] = inf;
            }
        }
    }
    int cnt = 0;
    for(int i=0; i<m; i++){
        int x, y, c;
        cin >> x >> y >> c;
        x--;
        y--;
        d[x][y] = c;
        d[y][x] = c;
        edge e;

        e.from = x;
        e.to = y;
        e.cost = c;
        dist.push_back(e);
        e.from = y;
        e.to = x;
        e.cost = c;
        dist.push_back(e);

    }

    warshall_floyd();
    int ans = 0;
    for(int i=0; i<dist.size(); i++){
        bool flag = false;
        for(int s=0; s<n; s++){
            for(int t=0; t<n; t++){
                if(d[s][dist[i].from] + dist[i].cost + d[dist[i].to][t] == d[s][t]){
                    flag = true;
                }
            }
        }
        if(!(flag)){
            ans++;
        }
    }
    cout << ans/2 << endl;
    return 0;
}