排队布局--差分约束

当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。

农夫约翰有 N 头奶牛,编号从 1 到 N,沿一条直线站着等候喂食。

奶牛排在队伍中的顺序和它们的编号是相同的。

因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。

如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。

一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数 L。

另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数 D。

给出 ML 条关于两头奶牛间有好感的描述,再给出 MD 条关于两头奶牛间存有反感的描述。

你的工作是:如果不存在满足要求的方案,输出-1;如果 1 号奶牛和 N 号奶牛间的距离可以任意大,输出-2;否则,计算出在满足所有要求的情况下,1 号奶牛和 N 号奶牛间可能的最大距离。

输入格式
第一行包含三个整数 N,ML,MD。

接下来 ML 行,每行包含三个正整数 A,B,L,表示奶牛 A 和奶牛 B 至多相隔 L 的距离。

再接下来 MD 行,每行包含三个正整数 A,B,D,表示奶牛 A 和奶牛 B 至少相隔 D 的距离。

输出格式
输出一个整数,如果不存在满足要求的方案,输出-1;如果 1 号奶牛和 N 号奶牛间的距离可以任意大,输出-2;否则,输出在满足所有要求的情况下,1 号奶牛和 N 号奶牛间可能的最大距离。

数据范围
2≤N≤1000,
1≤ML,MD≤104,
1≤L,D≤106
输入样例:
4 2 1
1 3 10
2 4 20
2 3 3
输出样例:
27
思路
很明显 题目给的就是 xb-xa<=l xb-xa>=d 差分约束的题目
题目所求1到n间的最大距离
求最短路求Xk<=0 的最大解
-1 即存在负环 -2 即到达不了n点
注意
存在这样的负环 与超级源点相连的负环
3 1 1
2 3 2
2 3 3
spfa如果从1开始走并不会判断出这个负环
而spfa 只从0开始走,如果边权都为正值,dist[i] 将全更新为0 如
4 2 1
1 3 10
2 4 20
2 3 3
答案显然不对
所以需要先走一遍spfa(0)判断是否存在负环
再走一遍spfa(1) 判断能否走到n 以及1到n的最大距离

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int h[N],idx,ne[N],e[N],w[N]; 
void add(int a,int b,int c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int n,ml,md;
int dist[N],st[N],se[N];
int spfa(int s){
    memset(se,0,sizeof se);
    memset(st,0,sizeof st);
    memset(dist,0x3f,sizeof dist);//初始化 spfa用了两次
	queue<int> q; q.push(s);dist[s]=0;st[s]=1,se[s]=1;
	while(q.size()){
		int t=q.front();q.pop();st[t]=0;
		for(int i=h[t];i!=-1;i=ne[i]){
			int j=e[i];
			if(dist[j]>dist[t]+w[i]){
				dist[j]=dist[t]+w[i];
				se[j]=se[t]+1; if(se[j]>n+1) return -1;//负环判断 从0开始的 n+1 从1开始的 n 直接写成n+1 
				if(!st[j]) q.push(j),st[j]=1;
			}
		}
	}
	return dist[n];
}
int main(){
	cin>>n>>ml>>md;
	memset(h,-1,sizeof h);
	for(int i=1;i<=ml;i++){
		int a,b,c;cin>>a>>b>>c;
		add(a,b,c);
	}
	for(int i=1;i<=md;i++){
		int a,b,c;cin>>a>>b>>c;
		add(b,a,-c);
	}
	for(int i=1;i<=n;i++) add(i+1,i,0);// 后一头牛 要比前一头牛 距离大 x(i)-x(i+1)<=0
    for (int i = 1; i <= n; i++) {//加入超级源点
        add(0, i, 0); 
    }
	int j=spfa(0);
	if(j==-1) cout<<-1;
	else   { 
	    int t=spfa(1);
	    if(t==0x3f3f3f3f) cout<<-2;	else cout<<dist[n];
	    }
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
华为OD机试真题-学生重新排队是一个典的编程问题,下面是问题和解决路: 问题描述: 有n个学生站成一排,每个学生都有一个独一无二身份ID。现在给定一个初始的学生排列顺序,以及一系列的交换操作,交换操作表示将两个学生的位置进行交换。请你编写一个算法,输出最终的学生排列顺序。 解决思路: 这个问题可以使用数组来表示学生的排列顺序。首先,我们需要根据初始的学生排列顺序构建一个映射表,将每个学生的ID与其在数组中的位置对应起来。然后,我们按照给定的交换操作,更新映射表中学生的位置信息。最后,根据更新后的映射表,构建最终的学生排列顺序。 具体步骤如下: 1. 构建映射表:遍历初始的学生排列顺序,将每个学生的ID与其在数组中的位置对应起来,可以使用哈希表来实现。 2. 执行交换操作:按照给定的交换操作,更新映射表中学生的位置信息。 3. 构建最终的学生排列顺序:根据更新后的映射表,构建最终的学生排列顺序。 下面是一个示例代码,用于解决这个问题: ```python def rearrange_students(initial_order, swap_operations): # 构建映射表 mapping = {} for i, student_id in enumerate(initial_order): mapping[student_id] = i # 执行交换操作 for swap in swap_operations: student1, student2 = swap mapping[student1], mapping[student2] = mapping[student2], mapping[student1] # 构建最终的学生排列顺序 final_order = [0] * len(initial_order) for student_id, position in mapping.items(): final_order[position] = student_id return final_order ``` 使用上述代码,你可以通过传入初始的学生排列顺序和交换操作,得到最终的学生排列顺序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值