题目描述
传送门
题目大意:n头牛编号为1到n,按照编号的顺序排成一列,每两头牛的之间的距离 >= 0。这些牛的距离存在着一些约束关系:1.有ml组(u, v, w)的约束关系,表示牛[u]和牛[v]之间的距离必须 <= w。2.有md组(u, v, w)的约束关系,表示牛[u]和牛[v]之间的距离必须 >= w。问如果这n头无法排成队伍,则输出-1,如果牛[1]和牛[n]的距离可以无限远,则输出-2,否则则输出牛[1]和牛[n]之间的最大距离。
题解
先贴一个不错的关于差分约束的讲解
将所有的限制都转换成
y−x<=z
的形式,然后x->y权值为z,然后跑最短路即可。
注意判负环和判断1,n的连通性。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#define N 200003
#define inf 1000000000
using namespace std;
int tot,n,m1,m2,point[N],nxt[N],v[N],dis[N],c[N],can[N],cnt[N];
void add(int x,int y,int z)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
}
int spfa()
{
for (int i=1;i<=n;i++) dis[i]=inf;
for (int i=1;i<=n;i++) can[i]=0,cnt[i]=0;
can[1]=1; dis[1]=0; cnt[1]=1;
queue<int> p; p.push(1);
while (!p.empty()){
int now=p.front(); p.pop();
for (int i=point[now];i;i=nxt[i])
if (dis[v[i]]>dis[now]+c[i]) {
dis[v[i]]=dis[now]+c[i];
if (!can[v[i]]) {
can[v[i]]=1;
cnt[v[i]]++;
if (cnt[v[i]]>n) return -1;
p.push(v[i]);
}
}
can[now]=0;
}
if (dis[n]==inf) return -2;
return dis[n];
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&m1,&m2);
for (int i=1;i<=m1;i++) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
if (x>y) swap(x,y);
add(x,y,z);
}
for (int i=1;i<=m2;i++) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
if (x>y) swap(x,y);
add(y,x,-z);
}
printf("%d\n",spfa());
}