AtCoder BC074 D: Restoring Road Network

問題

https://beta.atcoder.jp/contests/abc074/tasks/arc083_b

解法

ワーシャルフロイド法をベースにしてその考え方を応用することで解けます。

問題を「道路の構造が存在するかどうか」と「存在する道路の長さの和が最小となるようなもの」の二つに分けて考えます。

  • 道路の構造が存在するかどうか

表Aが「都市間の道路に沿った最短距離を表した表」なので、表Aに対してワーシャルフロイド法を適用し、表内の値が更新されることがあった場合に表Aは矛盾することになります。

例えば、(iからjへの距離)> (iからkへの距離)+(kからjへの距離)のような場合に、表Aはそもそも矛盾することになります。

よってそのような組み合わせが一つでもあれば、'-1'を出力して終了すれば良いです。

  • 存在する道路の長さの和が最小となるようなもの

どのような場合に道路が存在しないといけないかを考えます。

表Aは各都市間の最短経路を表しているので、iからjへの経路を考える場合、

(iからjへの距離)= (iからkへの距離)+(kからjへの距離)

のようなkが存在した場合、k経由で迂回しても距離は変わらないので、iからjへの道路は不要ということになります。

よって、表のサイズと同じ表を用意しておき、道路が必要か不要かをtrue/falseなどで記憶しておき、最後にtrueな経路の距離だけ加算すればよいです。

実装

#include<iostream>

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)   FOR(i,0,n)
#define MOD 1000000007

using namespace std;

typedef long long int ll;

const ll INF=(ll)1e18;

int main(){
    int N;

    cin >> N;

    ll a[N][N];
    bool f[N][N];

    REP(i,N)REP(j,N)cin >> a[i][j];
    REP(i,N)REP(j,N)f[i][j] = true;

    REP(k,N)REP(i,N)REP(j,N){
        if(a[i][k] + a[k][j] < a[i][j]){
            cout << -1 << endl;
            return 0;
        }else if(a[i][k] + a[k][j] == a[i][j] && i != k && k != j){
            f[i][j] = false;
        }
    }

    ll ans = 0;
    REP(i,N)REP(j,N){
        if(f[i][j])ans+=a[i][j];
    }

    cout << ans / 2 << endl;
}