zz's Mysterious Present(HDU 2145)---多源单汇最短路问题+排序

题目链接

题目描述

There are m people in n cities, and they all want to attend the party which hold by zz. They set out at the same time, and they all will choose the best way they think, but due to someone take a ride, someone drive, and someone take a taxi, they have different speed. Can you find out who will get zz’s mysterious present? The first one get the party will get the present . If there are several people get at the same time, the one who stay in the city which is farther from the city where is zz at begin will get the present. If there are several people get at the same time and the distance from the city he is at begin to the city where zz is, the one who has the larger number will get the present.
For the given cargo truck, maximizing the height of the goods transported is equivalent to maximizing the amount of goods transported. For safety reasons, there is a certain height limit for the cargo truck which cannot be exceeded.

输入格式

The first line: three integers n, m and k. m is the total number of the people, and n is the total number of cities, and k is the number of the way.(0<n<=300, 0<m<=n, 0<k<5000)
The second line to the (k+1)th line: three integers a, b and c. There is a way from a to b, and the length of the way is c.(0<a,b<=n, 0<c<=100)
The (k+2)th line: one integer p(0<p<=n), p is the city where zz is.
The (k+3)th line: m integers. the ith people is at the place p[i] at begin.(0<p[i]<=n)
The (k+4)th line: m integers. the speed of the ith people is speed[i];(0<speed[i]<=100)
All the ways are directed.

输出格式

For each case, output the one who get the present in one line. If no one can get the present, output “No one”.

输入样例

3 1 3
1 2 2
1 3 3
2 3 1
3
2
1

输出样例

1

分析

题目大意是有n个城市、k条有向路线和m个人,每个人都有各自的运动速度和起始地点,求这m个人中最先到达zz所在城市的编号。
由于每个人的运动速度是恒定的,那么他们的最小到达时间取决于这个人到zz城市的最短距离,因此本题就只用解决两个问题:①m个人到xx的最短距离②这m个人最短时间到达的最大编号。
对于问题①这种多起点单汇点的问题,通常是通过建立反图来求得各自的最短路径的;而对于问题②,只需要对照问题①得出来的最短距离计算各自的运动时间排序即可,注意时间是double类型的,判断是否相等通过其精度,不过数据貌似太水没卡。
以下是分别用dijkstra、SPFA和SPFA(SLF优化)算法写成的源码。

源程序

Dijkstra算法

#include <bits/stdc++.h>
#define MAXN 305
#define INF 0x3f3f3f3f
#define EXP 1e-8	//精度控制 
using namespace std;
struct Node{
	double tim;
	int id,dis;
	bool operator <(const Node a)const{
		if(fabs(tim-a.tim)>EXP) return tim>a.tim;	//不相等(小于精度)时按时间排序 
		else if(dis!=a.dis) return dis<a.dis;
		else return id<a.id;
	}
};
struct Edge{	//链式前向星 
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
	bool operator <(const Edge a)const{
		return w>a.w;
	};
}edge[MAXN*20];
int EdgeCount,head[MAXN];
int n,m,k,s,dis[MAXN],city[MAXN],speed[MAXN];
bool used[MAXN];
void addEdge(int u,int v,int w)	//链式前向星建图 
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void dijkstra()
{
	priority_queue<Edge> q;
	memset(dis,0x3f,sizeof(dis));
	memset(used,false,sizeof(used));
	dis[s]=0;
	q.push(Edge{s,0,0});
	while(!q.empty()){
		int u=q.top().v;q.pop();
		if(used[u])continue;
		used[u]=true;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push(Edge{v,dis[v],0});
			}
		}
	}
}
int main()
{
	while(~scanf("%d%d%d",&n,&k,&m)){	//城市数、人口数、边数
		memset(head,0,sizeof(head));
		EdgeCount=0;
		for(int i=1;i<=m;i++){	//建反图 
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			addEdge(v,u,w);
		}
		scanf("%d",&s);	//反图起点 
		dijkstra();
		priority_queue<Node> q;	 
		for(int i=1;i<=k;i++)scanf("%d",&city[i]);	//读入数据 
		for(int i=1;i<=k;i++){
			scanf("%d",&speed[i]);
			if(dis[city[i]]!=INF)q.push(Node{dis[city[i]]*1.0/speed[i],i,dis[city[i]]});
		}
		if(q.size()>0)printf("%d\n",q.top().id);
		else printf("No one\n");
	}
}

SPFA算法

#include <bits/stdc++.h>
#define MAXN 305
#define INF 0x3f3f3f3f
#define EXP 1e-8	//精度控制 
using namespace std;
struct Node{
	double tim;
	int id,dis;
	bool operator <(const Node a)const{
		if(fabs(tim-a.tim)>EXP) return tim>a.tim;	//不相等(小于精度)时按时间排序 
		else if(dis!=a.dis) return dis<a.dis;
		else return id<a.id;
	}
};
struct Edge{	//链式前向星 
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
	bool operator <(const Edge a)const{
		return w>a.w;
	};
}edge[MAXN*20];
int EdgeCount,head[MAXN];
int n,m,k,s,dis[MAXN],ven[MAXN],city[MAXN],speed[MAXN]; 
void addEdge(int u,int v,int w)	//链式前向星建图 
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void SPFA()
{
	queue<int> q;
	memset(dis,0x3f,sizeof(dis));
	memset(ven,0,sizeof(ven));
	dis[s]=0;
	ven[s]=1;
	q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();
		ven[u]=0;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				if(!ven[v]){
					q.push(v);
					ven[v]=1;
				}
			}
		}
	}
}
int main()
{
	while(~scanf("%d%d%d",&n,&k,&m)){	//城市数、人口数、边数
		memset(head,0,sizeof(head));
		EdgeCount=0;
		for(int i=1;i<=m;i++){	//建反图 
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			addEdge(v,u,w);
		}
		scanf("%d",&s);	//反图起点 
		SPFA();
		priority_queue<Node> q;	 
		for(int i=1;i<=k;i++)scanf("%d",&city[i]);	//读入数据 
		for(int i=1;i<=k;i++){
			scanf("%d",&speed[i]);
			if(dis[city[i]]!=INF)q.push(Node{dis[city[i]]*1.0/speed[i],i,dis[city[i]]});
		}
		if(q.size()>0)printf("%d\n",q.top().id);
		else printf("No one\n");
	}
}

SPFA算法之SLF优化

#include <bits/stdc++.h>
#define MAXN 305
#define INF 0x3f3f3f3f
#define EXP 1e-8	//精度控制 
using namespace std;
struct Node{
	double tim;
	int id,dis;
	bool operator <(const Node a)const{
		if(fabs(tim-a.tim)>EXP) return tim>a.tim;	//不相等(小于精度)时按时间排序 
		else if(dis!=a.dis) return dis<a.dis;
		else return id<a.id;
	}
};
struct Edge{	//链式前向星 
	int v,w,next;
	Edge(){};
	Edge(int _v,int _w,int _next){
		v=_v,w=_w,next=_next;
	};
	bool operator <(const Edge a)const{
		return w>a.w;
	};
}edge[MAXN*20];
int EdgeCount,head[MAXN];
int n,m,k,s,dis[MAXN],ven[MAXN],city[MAXN],speed[MAXN]; 
void addEdge(int u,int v,int w)	//链式前向星建图 
{
	edge[++EdgeCount]=Edge(v,w,head[u]);
	head[u]=EdgeCount;
}
void SPFA()
{
	deque<int> q;
	memset(dis,0x3f,sizeof(dis));
	memset(ven,0,sizeof(ven));
	dis[s]=0;
	ven[s]=1;
	q.push_back(s);
	int k;
	while(k=q.size()){
		int u=q.front();q.pop_front();
		ven[u]=0;
		for(int i=head[u];i;i=edge[i].next){
			int v=edge[i].v,w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				if(!ven[v]){
					if(k>1&&dis[v]<dis[q.front()])q.push_front(v);
					else q.push_back(v);					
					ven[v]=1;
				}
			}
		}
	}
}
int main()
{
	while(~scanf("%d%d%d",&n,&k,&m)){	//城市数、人口数、边数
		memset(head,0,sizeof(head));
		EdgeCount=0;
		for(int i=1;i<=m;i++){	//建反图 
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			addEdge(v,u,w);
		}
		scanf("%d",&s);	//反图起点 
		SPFA();
		priority_queue<Node> q;	 
		for(int i=1;i<=k;i++)scanf("%d",&city[i]);	//读入数据 
		for(int i=1;i<=k;i++){
			scanf("%d",&speed[i]);
			if(dis[city[i]]!=INF)q.push(Node{dis[city[i]]*1.0/speed[i],i,dis[city[i]]});
		}
		if(q.size()>0)printf("%d\n",q.top().id);
		else printf("No one\n");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值