洛谷5960:【模板】差分约束算法——题解

https://www.luogu.com.cn/problem/P5960

虽然说知道这玩意可是从来没写过……同时记录差分约束原理。

对于给定的式子$x-y\le c$,移动之得$x\le y+c$。

转换为图论模型,做起点,终点,权值为$y,x,c$的边,可发现如果我们对这个图跑最短路(先不要管怎么跑出来的233),那么一定有$dis[x]\le dis[y]+c$。

也就是说,此时每个点的$dis$值即为一组解,自然,有负环时无解。

现在就是怎么跑最短路的问题了,如果我们随便取一些点那么就会有一些点跑不到,就会出问题,于是我们设一个起点,对每条边连一条边权为0的单向边,这样我们只需要对这个起点跑一次spfa即可。

其本质是多构造了$u\le $起点的不等式。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5e3+5;
const int M=1e4+5;
const int INF=1e9;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int w,to,nxt;
}e[M];
int n,m,k,p,cnt,head[N],dis[N],sum[N];
bool vis[N];
inline void add(int u,int v,int w){
    e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
queue<int>q;
bool spfa(int s){
    for(int i=0;i<=n;i++)dis[i]=INF,sum[i]=0;
    q.push(s);vis[s]=1;dis[s]=0;sum[s]++;
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to,w=e[i].w;
            if(dis[v]-w>dis[u]){
                dis[v]=dis[u]+w;
                if(!vis[v]){
                    if(++sum[v]>=n+1)return 1;
                    q.push(v);vis[v]=1;
                }
            }
        }
    }
    return 0;
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)add(0,i,0);
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        add(v,u,w);
    }
    if(spfa(0))puts("NO");
    else{
        for(int i=1;i<=n;i++)printf("%d ",dis[i]);
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2020-02-02 18:24  luyouqi233  阅读(199)  评论(0编辑  收藏  举报