一个约束差分的小问题
查看原帖
一个约束差分的小问题
763077
Pjkang楼主2023/9/6 18:57

如果我用 a-1>=b的形式建边,得到的图就是求最短路满足条件。那么我是否可以求出最短路的最小值后,将每个点的值加上这个最小值+1,使得每个点大于0,这样得到答案呢?但是好像和答案差得有点多...

/// 最短路练习
/// 差分约束 + tarjan(scc缩点)

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 200000;

struct Edge {
    int to, cost;
    Edge (int to, int cost): to(to), cost(cost) {}
};

vector<Edge> G[N], Tree[N];
int dis[N];
vector<int> scc[N];
int dfn[N], low[N], c[N];
int cnt = 1, num = 1;
stack<int> stk; int ins[N];
int ind[N];
int n, m, S;

void tarjan(int x) {  // 只搜0权边,缩点
    dfn[x]= low[x] = num++;
    stk.push(x); ins[x] = 1;
    for (int i = 0; i < G[x].size(); i++) {
        Edge e = G[x][i];
        if (e.cost != 0) continue;
        if (!dfn[e.to]) {
            tarjan(e.to);
            low[x] = min(low[x], low[e.to]);
        }
        else if (ins[e.to]) {
            low[x] = min(low[x], dfn[e.to]);
        }
    }
    if (low[x] == dfn[x]) {
        int z;
        while (true) {
            z = stk.top(); stk.pop();
            scc[cnt].emplace_back(z);
            c[z] = cnt; ins[z] = 0;
            if (z == x) break;
        }
        if (x == 0) S = cnt;
        cnt++;
    }
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) G[0].emplace_back(i, 0);
    for (int i = 1; i <= m; i++) {
        int x, a, b; cin >> x >> a >> b;
        if (x == 1) {
            G[a].emplace_back(b, 0);
            G[b].emplace_back(a, 0);
        }
        else if (x == 2) {
            G[b].emplace_back(a, -1);
        }
        else if (x == 3) {
            G[a].emplace_back(b, 0);
        }
        else if (x == 4) {
            G[a].emplace_back(b, -1);
        }
        else if (x == 5) {
            G[b].emplace_back(a, 0);
        }
    }
    /// spfa 时间复杂度太玄乎了,用 tarjan缩点
    for (int i = 0; i <= n; i++) {
        if (!dfn[i]) tarjan(i);
    }
    for (int i = 0; i <= n; i++) {
        for (auto j: G[i]) {
            if (j.cost == -1) {
                if (c[i] == c[j.to]) {
                    cout << -1 << endl;
                    return;
                }
            }
        }
    }
    for (int i = 0; i <= n; i++) {
        for (auto j: G[i]) {
            if (c[i] != c[j.to]) {
                Tree[c[i]].emplace_back(c[j.to], j.cost);
                ind[c[j.to]]++;
            }
        }
    }
    /// 直接拓扑排序判断负
    fill(dis, dis+cnt+10, 2e9);
    int ans = 0, minn = 0;
    queue<int> q;
    for (int i = 1; i < cnt; i++) {
        if (ind[i] == 0) {
            dis[i] = 0;
            q.push(i);
        }
    }
    dis[S] = 0; int count = 0;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        count++;
        for (auto i: Tree[u]) {
            if (dis[i.to] > dis[u]+i.cost) {
                dis[i.to] = dis[u]+i.cost;
                minn = min(minn, dis[i.to]);
//                ans += dis[i.to]*(int)scc[i.to].size();
            }
            ind[i.to]--;
            if (ind[i.to] == 0) q.push(i.to);
        }
    }
    for (int i = 1; i < cnt; i++) {
        ans += dis[i]*(int)scc[i].size();
    }
    if (count != cnt-1) cout << -1 << endl;
    else cout << ans+(-1*minn*n)+n << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    solve();
    return 0;
}
2023/9/6 18:57
加载中...