1. 程式人生 > 實用技巧 >洛谷 P5960 【模板】差分約束演算法(差分約束)

洛谷 P5960 【模板】差分約束演算法(差分約束)

題目連結:https://www.luogu.com.cn/problem/P5960

題目中x1-x'1<=y1可以轉變為

    x1<=x'1+y1

換一下字母更顯然易見:dis[v]<=dis[u]+edge[i].w

那麼便可以轉換成圖上的最短路問題(解集),因為題中並沒有說明是聯通圖,可以設一個超級源點,然後向每個節點連一條邊權為0的邊,然後從0點開始做最短路。

注意建邊是從x'1連向x1。

AC程式碼:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<queue>
 5
using namespace std; 6 int n,m,tot; 7 const int N=5005; 8 struct node{ 9 int to,next,w; 10 }edge[N<<1]; 11 int head[N],dis[N],vis[N],in[N]; 12 void add(int u,int v,int w){ 13 edge[tot].to=v; 14 edge[tot].next=head[u]; 15 edge[tot].w=w; 16 head[u]=tot++; 17 } 18 bool spfa(int
u){ 19 queue<int> q; 20 q.push(u);vis[u]=1;dis[u]=0; 21 while(!q.empty()){ 22 u=q.front();q.pop();vis[u]=0; 23 if(in[u]==n) return 0; 24 for(int i=head[u];i!=-1;i=edge[i].next){ 25 int v=edge[i].to; 26 if(dis[v]>=dis[u]+edge[i].w){ 27
dis[v]=dis[u]+edge[i].w; 28 in[v]++; 29 if(!vis[v]){q.push(v);vis[v]=1;} 30 } 31 } 32 } 33 return 1; 34 } 35 int main(){ 36 memset(head,-1,sizeof(head)); 37 memset(dis,0x3f3f,sizeof(dis)); 38 scanf("%d%d",&n,&m); 39 for(int i=1;i<=m;i++){ 40 int u,v,w; 41 scanf("%d%d%d",&u,&v,&w); 42 add(v,u,w); 43 } 44 for(int i=1;i<=n;i++) add(0,i,0); 45 if(spfa(0)==0){printf("NO"); return 0;} 46 for(int i=1;i<=n;i++) printf("%d ",dis[i]); 47 return 0; 48 }
AC程式碼