设计【SPFA】【差分约束】
题目大意:
有头牛,现在要设计一个顺序让他们站成一排给他们喂食。奶牛们按照编号顺序依次站立,允许有多只牛站在同一位置。有一些牛希望之间的距离在某个范围内,也有一些牛希望两之间的距离大于等于某个距离。如果存在某种方案满足上述要求,请你输出号牛和号牛之间最大距离。
4 2 1
1 3 10
2 4 20
2 3 3
27
思路:
考场上就想到是最短路,但是没能打出来。
我们可以把每头牛看成一个点,如果两头牛希望之间的距离小于某个范围,就在这两头牛之间连一条长度为范围的单向边(小号牛连向大号牛),如果两头牛希望之间的距离大于某个范围,就在这两头牛之间连一条长度为负范围的单向边(大号牛连向小号牛),建完图之后,跑一边SPFA,如果有答案,输出答案,如果没能到达点,那么输出(距离可以无限),如果循环打到了一定次数(我设的是),那么说明出现了环,就不存在这样的方案。
代码:
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
const int INF=99999999;
int n,m1,m2,dep,x,y,z,head[200001],vis[200001],dis[200001],t;
bool ok;
struct edge
{
int next,to,dis;
}e[200001];
void add(int from,int to,int d)
{
t++;
e[t].dis=d;
e[t].to=to;
e[t].next=head[from];
head[from]=t;
}
void spfa()
{
ok=true;
queue<int> q;
for (int i=1;i<=n;i++) //初始化
{
vis[i]=0;
dis[i]=INF;
}
q.push(1);
vis[1]=1;
dis[1]=0;
while (q.size())
{
int u=q.front();
q.pop();
vis[u]=0;
dep++; //深度+1,记录循环次数
if (dep>3*n) //循环打到一定次数
{
ok=false;
printf("-1\n");
return;
}
for (int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if (dis[v]>dis[u]+e[i].dis) //更新距离
{
dis[v]=dis[u]+e[i].dis;
if (!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m1,&m2);
for (int i=1;i<=m1;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z); //互相喜欢
}
for (int i=1;i<=m2;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(y,x,-z); //互相讨厌
}
spfa();
if (!ok) return 0;
if (dis[n]==INF) return printf("-2\n")&0;
else return printf("%d\n",dis[n])&0;
}