我与差分约束

前言

  • 偶然发现一道计蒜客的题,让我差分约束,最大化 \(|X_1-X_n|\)。也没多想以为是什么我不知道的。
  • 于是去问 yb,他说你二分呗!这很对呀,\bx\bx 但应不止于此。
  • 直到发现了这篇文章

正文

  • 差分约束,我自认为再熟悉不过了,利用最短路的不等式,\(dis_u+w\ge dis_v\)
  • 额,当时写差分约束时有一个问题。为什么要有一个超级源点,连向所有的点,点权为 \(0\)
  • 正如大多数题解所说的,为了对于每个点跑满限制,防止图不联通。
  • 嗯,但是,这真没改变我们的原图吗,其实确实改变了,但如果你只是想判断是否可行,是没有影响的。
  • 自认为,最正规的做法,应该是,初始化所有点的 \(dis_u=inf\),拿出一个整个系统的钦定点,\(rt\),令 \(dis_{rt}=initval\)
  • 之后把所有点全部放入 spfa 的初始队列,这样跑的不是多源汇最短路,只是更新了所有边而已。
  • 这有什么用呢?最大的用处,它没有破坏原图的性质。
  • \(p(u,v)\) 表示一条 \(u\)\(v\) 的路径,显然有 \(dis_u+p(u,v)\ge dis_v\)
  • \(u\) 换成 \(rt\)\(p(rt,v)\ge dis_v-dis_{rt}\),显然 固定 \(rt,dis_{rt}\) 跑最短路,若我们想取 \(dis_v\) 的最大值,显然为 \(p(rt,v)\) 的最小值 加上 \(dis_{rt}\)。你会发现,这恰为最短路 \(dis_{v}\) 的结果。
  • 同理,若是最长路,得到的就是,最小的 \(dis_v\) 的结果。
  • 至此,本文结束。
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
const int N = 5500;
typedef int ll;
const ll inf = 0x3f3f3f3f;
struct node { int v; ll w; };
vector<node> G[N]; ll dis[N]; int cnt[N], vis[N];
int main()
{
    int n, m; cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v; ll w; cin >> u >> v >> w;
        G[v].push_back({ u,w });
    }
    queue<int> q;
    for (int i = 1; i <= n; i++)q.push(i), dis[i] = inf, vis[i] = 1;
    dis[1] = 0;
    while (q.size())
    {
        int u = q.front(); q.pop(); vis[u] = 0;
        for (auto [v, w] : G[u])
        {
            if (dis[u] + w < dis[v])
            {
                dis[v] = dis[u] + w; cnt[v] = cnt[u] + 1;
                if (cnt[v] > n) { cout << "NO\n"; return 0; }
                if (!vis[v])vis[v] = true, q.push(v);
            }
        }
    }
    for (int i = 1; i <= n; i++)cout << dis[i] << ' '; cout << '\n';
    return 0;
}
posted @ 2025-02-10 08:33  LUHCUH  阅读(31)  评论(0)    收藏  举报