题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1731
差分约束;
ML: dis[y] - dis[x] <= k,即 x 向 y 连边权为 k 的边;
MD: dis[y] - dis[x] >= k,即 y 向 x 连边权为 -k 的边;
有负环说明要 <= 的 k 无限小,所以无解,输出 -1;
走不到说明 1 与 n 之间无限制关系,所以 dis[n] 可以无限大,输出 -2;
还要注意隐藏条件是编号小的在编号大的前面,所以还有 dis[x-1] <= dis[x];
注意 spfa 判负环那里是松弛次数不超过 n 而不是入队次数(入队次数也可以?总之WA了...)。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; typedef long long ll; int const xn=1005,xm=20005+xn;//!!! int n,ml,md,hd[xn],ct,to[xm],nxt[xm],w[xm],cnt[xn]; ll dis[xn]; bool vis[xn]; queue<int>q; void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;} int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } ll spfa() { memset(dis,0x3f,sizeof dis); ll inf=dis[1];//ll dis[1]=0; q.push(1); cnt[1]=1; vis[1]=1; while(q.size()) { int x=q.front(); q.pop(); vis[x]=0; for(int i=hd[x],u;i;i=nxt[i]) if(dis[u=to[i]]>dis[x]+w[i]) { dis[u]=dis[x]+w[i]; if(!vis[u])vis[u]=1,q.push(u); cnt[u]++;//不一定入队 if(cnt[u]>=n)return -1; } } if(dis[n]==inf)return -2; return dis[n]; } int main() { n=rd(); ml=rd(); md=rd(); for(int i=1,x,y,z;i<=ml;i++) { x=rd(); y=rd(); z=rd(); add(x,y,z); } for(int i=1,x,y,z;i<=md;i++) { x=rd(); y=rd(); z=rd(); add(y,x,-z); } for(int x=2;x<=n;x++)add(x,x-1,0); printf("%lld ",spfa()); return 0; }