[筆記]差分約束演算法
阿新 • • 發佈:2020-08-22
[筆記]差分約束演算法
原題鏈
演算法
題目給出了幾個刑辱x1 - x2≤y1
的約束條件,我們可以將其移項,變形為x1≤y1+x2
,這就類似於最短路中的式子dis[y] ≤dis[x] + w[z]
,所以我們可以仿照最短路演算法.連一條從x2到x1的權值為y1的有向邊,這是我們新建一個虛擬節點0,將所有點i都連一條從0指向i的邊權為0的有向邊,因此問題的答案便成為了從0到任意節點i的最短路徑的長度,又因為與0相連的邊的權值為0,所以對答案沒有影響.
AC程式碼
#include <bits/stdc++.h> using namespace std; struct node{int to,next,w;}e[50010]; int fir[50010],tot = 0,times[50010],n,m; void add(int x,int y,int z){ tot++; e[tot].w = z; e[tot].to = y; e[tot].next = fir[x]; fir[x] = tot; return; } bool in[50010]; int dis[50010]; bool spfa(int x){ queue < int > q; for(int i = 1;i <= n;i++)dis[i] = 1e9; while(!q.empty()) q.pop(); memset(in,false,sizeof(in)); memset(times,0,sizeof(times)); in[x] = true; times[x]++; dis[x] = 0; q.push(x); while(!q.empty()){ int k = q.front(); q.pop();in[k] = false; for(int i = fir[k];i;i = e[i].next){ if(dis[e[i].to] > dis[k] + e[i].w){ dis[e[i].to] = dis[k] + e[i].w; if(!in[e[i].to]){ q.push(e[i].to); times[e[i].to]++; in[e[i].to] = true; if(times[e[i].to] > n) return false; } } } } return true; } int main(){ cin>>n>>m; for(int i = 1;i <= m;i++){ int x,y,z; cin>>x>>y>>z; add(y,x,z); } for(int i = 1;i <= n;i++){ add(0,i,0); } if(!spfa(0)){ cout<<"NO"<<endl; return 0; } for(int i = 1;i <= n;i++){ cout<<dis[i]<<" "; } cout<<endl; return 0; }