题意简述:
当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。FJ有N(2<=N<=1000)头奶牛,编号从1到N,沿一条直线站着等候喂食。奶牛排在队伍中的顺序和它们的编号是相同的。因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。即使说,如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。
一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数L。另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数D。给出ML条关于两头奶牛间有好感的描述,再给出MD条关于两头奶牛间存有反感的描述。(1<=ML,MD<=10000,1<=L,D<=1000000)
你的工作是:如果不存在满足要求的方案,输出-1;如果1号奶牛和N号
奶牛间的距离可以任意大,输出-2;否则,计算出在满足所有要求的情况下,1号奶牛和N号奶牛间可能的最大距离。
思路:
题目很简单,就是普通的差分约束系统,这里我不多讲了。
主要是那个最大距离,其实就是求1-n的最短路。如果真的有比最短路更大的路的话,那么肯定就会构成一个环,每循环一次就大一点,最后是无穷大了。
证明如下:(引用于一篇博客)
证明:设D[i]是顶点i和1的最短路径估计值,d[i]是顶点i和1可能的最大距离。
我们首先证明,d[n]<=D[n],运用反证法。
假如d[n]>D[n],那么在spfa运行之前,将赋予每个顶点i的充分大的值换成对应的d[i]。由于d本身满足所有约束条件,所以运行后,得出D'=d。由于充分大的值比所有d[i]都大,而求最短路运用的是逐步松弛操作,我们设立一个更大的初值不可能导致我们的终值反而更小。所以对于任意i,必定有D[i]>=D'[i],即有D[n]>=d[n],这与我们的假设矛盾。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define inf 1000000000
using namespace std;
int cnt,n;
queue<int> que;
struct node
{
int v,w,next;
}s[20009];
int head[1005];
void add(int u,int v,int w)
{
s[cnt].v=v;
s[cnt].w=w;
s[cnt].next=head[u];
head[u]=cnt++;
}
void spfa(int src)
{
while(!que.empty()) que.pop();
int vis[1005],dis[1005],num[1005];
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
dis[i]=inf;
dis[src]=0;
que.push(src);vis[src]=1;
while(!que.empty())
{
int t=que.front();
que.pop();vis[t]=0;
for(int i=head[t];i!=-1;i=s[i].next)
{
int v=s[i].v;
int w=s[i].w;
if(dis[v]>dis[t]+w)
{
dis[v]=dis[t]+w;
num[v]++;
if(num[v]>n)
{
printf("-1\n");
return ;
}
if(!vis[v])
{
vis[v]=1;
que.push(v);
}
}
}
}
if(dis[n]==inf)
printf("-2\n");
else
printf("%d\n",dis[n]);
}
int main()
{
//freopen("t.txt","r",stdin);
int ml,md,a,b,d;
while(scanf("%d%d%d",&n,&ml,&md)!=EOF)
{
cnt=0;
memset(head,-1,sizeof(head));
for(int i=0;i<ml;i++)
{
scanf("%d%d%d",&a,&b,&d);
add(a,b,d);
}
for(int i=0;i<md;i++)
{
scanf("%d%d%d",&a,&b,&d);
add(b,a,-d);
}
spfa(1);
}
return 0;
}