hdu6525——Subway Chasing(差分约束系统)

博客介绍了如何利用差分约束系统解决HDU 6525地铁追逐问题。内容包括题目描述、解题思路及如何建立最短路模型。通过分析每个询问的条件,构建不等式约束,并利用最短路算法求解满足条件的时间。
摘要由CSDN通过智能技术生成

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6252

题目大意:

第一个人比第二个人先走了x分钟,路上有n个车站,现在有m个询问,每次询问会得到第一个人位置和第二个人的位置,表示为

【A,B】【C,D】,意思是当前第一个人在A,B车站中间,第二个人在C,D中间,当B==A时表示第一个人恰好在A车站,第二个人同

理。现在问你车站之间可能的距离。

思路:

差分约束系统,这里有一篇讲的很好的文章,https://blog.csdn.net/my_sunshine26/article/details/72849441

这类题目的大概意思就是,给你很多很多个约束条件,比如xi-xj>=ak这样的不等式约束,问你能满足情况的条件,或者是另一个式子的最大/最小值

对于差分约束,可以将不等式变形为xj>=ak+xi,这样是不是与最短路的松弛操作很像?所以差分约束系统可以利用最短路建立模型并且求解。

具体如何建模可以参考上面的文章,这里用hdu6525这个题目练习一下

这个题目只需要求满足条件的时间,那么最小满足的条件肯定也是满足的,所以利用差分约束建模

首先,两个相邻的站台之间的空格肯定要小于等于1,即ai+1-ai<=1,所以ai>=ai+1+1

可以建边

其次,对于每一个询问,给出a,b,c,d四个数字,因为两个人的差距恒定为x,所以可以分情况讨论

  1. 如果a==b且c==d,那么两个站台的距离==x,可以用一个>=一个<=两个不等式进行约束
  2. 其他情况,等号无法取到,可以建边d-a>x和c-b<x

最后跑最短路模型,答案就是起点到各个点的最短距离,就是一个单源最短路

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define endl '\n'
#define sc(x) scanf("%lld",&x)

using namespace std;
const int inf=0xc0c0c0c0;
const int size=2005;
struct Edge{
	int u,v,w;
	Edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
};
vector<Edge> edge;
vector<int> No[2005];
int vis[2005];
int dis[2005];
int cnt[2005];
void init(int n)
{
 	fill(dis,dis+n+1,inf);
	memset(vis,0,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	for(int i=0;i<=n;i++) No[i].clear();
	edge.clear();
}
void addedge(int u,int v,int w)
{
	edge.push_back(Edge(u,v,w));
	No[u].push_back(edge.size()-1);
}
bool spfa(int s,int n)
{
	dis[s]=0;
	queue<int> Q;
	Q.push(s);
	while(!Q.empty())
	{
		int k=Q.front();
		Q.pop();
		vis[k]=0;
		for(int i=0;i<No[k].size();i++)
		{
			int id=No[k][i];
			if(dis[edge[id].v]<dis[k]+edge[id].w)
			{
				dis[edge[id].v]=dis[k]+edge[id].w;
				if(!vis[edge[id].v])
				{
					Q.push(edge[id].v);vis[edge[id].v]=1;
					if(++cnt[edge[id].v]>n) return false;
				}
			}
		}
	}
	return true;
}
int main()
{
	int n,m,x;
	int t;
	scanf("%d",&t);
	for(int kace =1;kace <= t ;kace++)
	{
		scanf("%d%d%d",&n,&m,&x);
		int i;
		init(n+1);
		for(int i=1;i<=n;i++)
		{
			addedge(i-1,i,1);
		}
		for(i=0;i<m;i++)
		{
			int a,b,c,d;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			int pf=0;
			if(a!=b||c!=d) pf=1;
			addedge(c,b,-x+pf);
			addedge(a,d,x+pf);
		}
		printf("Case #%d:",kace);
		if(spfa(0,n+1)&&dis[n]!=inf)
		for(int i=2;i<=n;i++)
		{
			printf(" %d",dis[i]-dis[i-1]);
		}
		else printf(" IMPOSSIBLE");
		puts("");
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值