题目大意:有n头牛排成一列,这些牛排列时候,有这个两个条件,A、B两头牛间的距离最大为D,或者A、B两头牛之间的距离至少为D,前ML个约束是第一种约束,后MD个约束是第二种约束,求第1头牛到第N头牛可能的最远距离。如果距离可以无限大,打印出-2, 如果不存在这样的排列打印出-1。
分析:限制一转化为不等式即为d[b] - d[a] <= D,即a->b的边的权值为D。限制条件二转化为不等式即为d[b] - d[a] >= D等价于d[a] - d[b] <= -d,即b->a的边权值为-D,求两个变量之间的最大值,就转化成了求最短路。
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn = 20005;
const int INF = 0x3f3f3f3f;
struct edge
{
int v, w, next;
}Edge[maxn];
int head[maxn], dis[maxn], time[maxn], cnt, n, ml, md;
bool vis[maxn];
void add_edge(int u, int v, int w)
{
Edge[cnt].v = v;
Edge[cnt].w = w;
Edge[cnt].next = head[u];
head[u] = cnt++;
}
int spfa(int s, int tol)
{
memset(dis, 63, sizeof(dis));
memset(time, 0, sizeof(time));
memset(vis, false, sizeof(vis));
dis[s] = 0;
vis[s] = true;
time[s]++;
queue<int> q;
q.push(s);
while(!q.empty())
{
int tem = q.front();
q.pop();
vis[tem] = false; //注意取消标记一定要放在这边,因为图的题目中一个点可能自身有负环
for(int i = head[tem]; i != -1; i = Edge[i].next)
{
int to = Edge[i].v;
if(dis[to] > dis[tem] + Edge[i].w)
{
dis[to] = dis[tem] + Edge[i].w;
if(!vis[to])
{
vis[to] = true;
q.push(to);
time[to]++;
if(time[to] >= tol) //如果入队列超过n次(点的个数), 那么就存在负环,因为一个图的最短路肯定由不大于n-1条边构成
return -1;
}
}
}
}
return dis[n];
}
int main()
{
int u, v, w;
while(cin >> n >> ml >> md)
{
cnt = 0;
fill(head, head + n + 1, -1);
for(int i = 0; i < ml; i++)
{
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
}
for(int i = 0; i < md; i++)
{
scanf("%d%d%d", &u, &v, &w);
add_edge(v, u, -w);
}
int ans = spfa(1, ml + md);
if(ans == -1)
cout << -1 << endl;
else if(ans == INF) //如果某相邻两头牛间的约束条件没有给出,那么这两头牛之间就可以无限大
cout << -2 << endl;
else
cout << dis[n] << endl;
}
return 0;
}