abc074d <Floyed 消除传递边>

发布时间 2023-07-11 09:30:31作者: O2iginal

D - Restoring Road Network

// https://atcoder.jp/contests/abc074/tasks/arc083_b
// <Floyed>
// 1. 跑一边floyed检查是否有边被更新, 从而判断是否A中所有都为最短路
// 2. 在Floyed过程中, 记录被更新的边 a[i][j], 这些边是传递产生的边, 没有必要
//   (想到了离散数学中的传递性, 偏序集的哈斯图 ??)
// 注意: 不能直接碰到传递边就 -a[i][j], 因为可能重复, 因而需要先标记, 后计算
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
using LL = long long;
const int N = 310;
int a[N][N];  // A
int b[N][N];  // backup
bool st[N][N];

void solv()
{
    int n;
    cin >> n;
    LL ans = 0;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= n; j ++)
        {
            cin >> a[i][j];
            b[i][j] = a[i][j];
            ans += a[i][j];
        }
    
    for (int k = 1; k <= n; k ++)
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
            {
                if (a[i][j] == a[i][k] + a[k][j] && i != k && j != k) 
                {
                    // ans -= a[i][j];  // 不能直接计算, 要先标记(避免重复计算)
                    st[i][j] = true;
                    // cout << "ij = " << i << " " << j << endl;
                }
                a[i][j] = min(a[i][k] + a[k][j], a[i][j]);
            }
    if (memcmp(a, b, sizeof a)) 
    {
        cout << -1 << endl;
        return;
    }
    else
    {
        for (int i = 1; i <= n; i ++)
            for (int j = 1; j <= n; j ++)
                if (st[i][j]) ans -= a[i][j];
        cout << ans / 2 << endl;
    }

}

int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = 1;
	// cin >> T;
    while (T --)
    {
        solv();
    }
    return 0;
}