poj3169

题意简述:

当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。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;
 } 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值