【Luogu】每日一题——Day14. P5960 【模板】差分约束 (图论 + 最短路)
链接:P5960 【模板】差分约束 - 洛谷
题目:
思路:
含多种讨论
我们将题目中的式子稍微变形,即 xc <= y + xc',此时的形态类似于 dis[u] <= dis[v] + w
即对短路,所以如果我们能找到一个最短路满足所有的 dis[c] <= dis[c'] + 1 即可,所以我们直接跑一遍最短路即可
具体的,我们增加一个超级点源,其到每个点的距离都是 0,然后跑一遍 SPFA
对于无解情况,显然是存在负环时无解,此时的方程不断替换最后会形如 x <= x - c,显然无解
对于其他变种,如 xc - xc' >= y,此时有 xc >= y + xc',即变为了求最长路,此时改变一下不等式即可
来自题解:
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
int n, m;
int vis[5005];
vector<vector<pair<int,int>>> g(5005);
int dis[5005];
int d[5005];
void solve()
{memset(dis, 0x3f, sizeof dis);cin >> n >> m;for (int i = 0; i < m; i++){int u, v, w;cin >> u >> v >> w;g[v].push_back({ u,w });}//超级点源for (int i = 1; i <= n; i++){g[0].push_back({ i ,0});}queue<int> q;q.push(0);vis[0] = 1;dis[0] = 0;while (!q.empty()){auto t = q.front();q.pop();vis[t] = 0;for (auto & son : g[t]){if (dis[son.first] > dis[t] + son.second){dis[son.first] = dis[t] + son.second;if (!vis[son.first]){d[son.first]++;if (d[son.first] == n+1){no;return;}q.push(son.first);vis[son.first];}}}}for (int i = 1; i <= n; i++){cout << dis[i] << " ";}cout << endl;
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}