POJ_3169_Layout_差分约束

好好写作业!


题意:

农夫约翰又有一群屌屌的奶牛,他们在一条线上吃东西,按照编号(从1到n)排序,有些牛互相之间不喜欢,他们希望之间的距离大于一个值,有些牛关系很好,他们希望吃东西的时候距离不超过一个值。在线上的一个点上可以有多只牛排队。



Input

Line 1: Three space-separated integers: N, ML, and MD.

Lines 2..ML+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at most D (1 <= D <= 1,000,000) apart.

Lines ML+2..ML+MD+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at least D (1 <= D <= 1,000,000) apart.

Output

Line 1: A single integer. If no line-up is possible, output -1. If cows 1 and N can be arbitrarily far apart, output -2. Otherwise output the greatest possible distance between cows 1 and N.


之前觉得很难很难的题,看题解也不懂,现在再看其实不难,就是个差分约束,感觉区域赛这种级别的比赛不会考裸算法,如果考最短路一定是在途中求一个最短路,或者像这个题一样,差分约束。

下列不等式默认j>i

根据按编号排序,有x[j]>=x[i]

根据ML,有d+x[i]>=x[j]

根据MD,有-d+x[j]>=x[i]

这样就得到了建立差分约束的边:从j到i,长为0;从i到j,长为d;从j到i,长为-d

用SPFA或者bellman即可

如果出现负环,则说明从i到j再到i存在负环,就说明存在冲突。

如果跑完SPFA,dist[n-1]仍为inf,则说明对它没有限制。

否则输出dist[n-1]即可

一开始只有一个错误,就是在SPFA时有的松弛没有进行,因为判读被松弛的点在队列里,但实际上这样可能会错过一些必须的松弛操作,应当判断是否在队列里选择是否入队,而不考虑是否松弛。



代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
#define mxn 1010
#define inf 0x3f3f3f3f
int mapp[mxn][mxn];
int n,ml,md;
int dist[mxn];
bool spfa(){
	queue<int> q;
	bool flag[mxn];
	int count[mxn];
	memset(dist,0x3f,sizeof(dist));
	while(!q.empty())	q.pop();
	memset(flag,false,sizeof(flag));
	memset(count,0,sizeof(count));
	q.push(0);
	dist[0]=0;
	while(!q.empty()){
		int now=q.front();
		if(count[now]>n)	return false;
		q.pop();
		flag[now]=false;
		for(int i=0;i<n;++i)	if(dist[now]+mapp[now][i]<dist[i]){
			dist[i]=dist[now]+mapp[now][i];
			if(flag[i])	continue;
			q.push(i);
			++count[i];
			flag[i]=true;
		}
	}
	return true;
}
int main(){
	while(scanf("%d%d%d",&n,&ml,&md)!=EOF){
		memset(mapp,0x3f,sizeof(mapp));
		for(int i=0;i<n-1;++i)
			mapp[i+1][i]=0;
		int a,b,d;
		for(int i=0;i<ml;++i){
			scanf("%d%d%d",&a,&b,&d);
			mapp[a-1][b-1]=d;
		}
		for(int i=0;i<md;++i){
			scanf("%d%d%d",&a,&b,&d);
			mapp[b-1][a-1]=-d;
		}
		bool ok=spfa();
		if(!ok)	puts("-1");
		else if(dist[n-1]==inf)	puts("-2");
		else	printf("%d\n",dist[n-1]);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值