LuoguP5960 【模板】差分约束算法

link


链接

分析

一下是粗略的证明
先假设这样的解是存在的,对未知数Xi,假设一共有k组差分约束,则容易推出Xi <= min{ , , ,}
而通过建边用spfa得到的结果显然是满足这个条件的。为了维护图的连通性,需要加入超级源点

粗略的证明

对于存在负环的情况,SPFA可以判断,此时负环的意义就是Xi <= Xi + 某负数,很显然不会存在符合差分约束的解。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>

using namespace std;

const int N = 1e5 + 10;
int dis[N], inq[N], tot[N], head[N];
int n, m, cnt = 0;

struct edge{
    
    
    int to, nxt, val;
}e[N];

inline void add(int u, int v, int w){
    
    
    e[++cnt].to = v;
    e[cnt].val = w;
    e[cnt].nxt = head[u];
    head[u] = cnt;
}

int spfa(){
    
    
    queue<int> que;
    que.push(0);
    dis[0] = 0;
    inq[0] = 1;
    while (!que.empty()){
    
    
        int u = que.front();
        que.pop();
        inq[u] = 0;
        for (int i = head[u]; ~i; i = e[i].nxt) {
    
    
            int v = e[i].to, w = e[i].val;
            if (dis[v] > dis[u] + w){
    
    
                dis[v] = dis[u] + w;
                if (!inq[v]){
    
    
                    if (++tot[v] > n) return 0;
                    que.push(v);
                    inq[v] = 1;
                }
            }
        }
    }
    return 1;
}

int main(){
    
    
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    memset(head, -1, sizeof head);
    memset(dis, 0x3f, sizeof dis);
    cin >> n >> m;
    for (int i = 0, u, v, w; i < m; ++i) {
    
    
        cin >> u >> v >> w;
        add(v, u, w);
    }
    for (int i = 1; i <= n; ++i) {
    
    
        add(0, i, 0);
    }
    if (!spfa()) cout << "NO" << endl;
    else
        for (int i = 1; i <= n; ++i) {
    
    
            cout << dis[i] << " ";
        }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_50070650/article/details/114270941
今日推荐