UVA - 10816[Travel in Desert]题解&代码

Travel in Desert

There is a group of adventurers
who like to travel in the desert. Everyone knows travelling in desert
can be very dangerous. That’s why
they plan their trip carefully every
time. There are a lot of factors to
consider before they make their final decision.
One of the most important factors is the weather. It is undesirable to travel under extremely high
temperature. They always try to
avoid going to the hottest place.
However, it is unavoidable sometimes as it might be on the only
way to the destination. To decide
where to go, they will pick a route that the highest temperature is minimized. If more than one route
satisfy this criterion, they will choose the shortest one.
There are several oases in the desert where they can take a rest. That means they are travelling
from oasis to oasis before reaching the destination. They know the lengths and the temperatures of the
paths between oases. You are to write a program and plan the route for them.
Input
Input consists of several test cases. Your program must process all of them.
The first line contains two integers N and E (1 ≤ N ≤ 100; 1 ≤ E ≤ 10000) where N represents the
number of oasis and E represents the number of paths between them. Next line contains two distinct
integers S and T (1 ≤ S, T ≤ N) representing the starting point and the destination respectively. The
following E lines are the information the group gathered. Each line contains 2 integers X, Y and 2 real
numbers R and D (1 ≤ X, Y ≤ N; 20 ≤ R ≤ 50; 0 < D ≤ 40). It means there is a path between X and
Y , with length D km and highest temperature RoC. Each real number has exactly one digit after the
decimal point. There might be more than one path between a pair of oases.
Output
Print two lines for each test case. The first line should give the route you find, and the second should
contain its length and maximum temperature.

Sample Input

6 9
1 6
1 2 37.1 10.2
2 3 40.5 20.7
3 4 42.8 19.0
3 1 38.3 15.8
4 5 39.7 11.1
6 3 36.0 22.5
5 6 43.9 10.2
2 6 44.2 15.2
4 6 34.2 17.4

Sample Output

1 3 6
38.3 38.3

题目大意:

有一群冒险家,他们喜欢在沙漠中旅行。每个人都知道在沙漠中旅行可能非常危险。这就是为什么他们每次旅行都仔细计划。有很多因素需要他们做最后决定之前考虑一下。
最重要的因素之一是天气。
在极高的温度下旅行是不可取的。他们总是试图避免去最热的地方。然而,它有时是不可避免的,因为它可能是唯一的去目的地的路。但他们会选择一条最高温度最小的路线。如果多于一条路线,满足这个条件,他们会选择最短的一个。
沙漠中有几个绿洲,他们可以在那里休息。这意味着他们可以从一个绿洲到另一个绿洲,然后到达目的地。它们知道绿洲之间路经的长度和温度。你要写一个程序,为他们计划路线。

输入格式:

输入由几个测试用例组成。您的程序必须处理所有这些。

第一行包含两个整数N和E (1≤N≤100;1 E≤10000) N代表绿洲总个数,E表示它们之间的路径数量。下一行包含两个不同的整数S和T (1≤(S, T≤N)分别代表的出发点和目的地。

下面几行是该组收集的信息。每一行包含2个整数X,Y和2个实数数字R和D (1≤X, Y≤N;20 R≤≤50;0 < D≤40)。这意味着在X和Y之间有一条路径,最高温度为R,长度为D公里。每个实数后面都有一位数小数点。在一对绿洲之间可能有多条路径。

输出格式:

为每个测试用例打印两行。
第一行应该给出你找到的路线。
第二行应该给出包含它的长度和最高温度(都保留一位小数)。

分析:

如果只考虑最小的最大温度,那么本题就是一个最小瓶颈路问题,只需按照温度找一棵最小生成树即可。但是,如果这样的路径有多个,实际上是最小生成树有多个时,要找到最短路径。我们可以将所有的边扫一遍,找到所有比最小的最大温度的边,重新构造一个图,然后再在这个图中找最短路。

代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
struct rec{ 
	int x,y;
	double z,t;
}k[500010];
int fa[100010];
priority_queue< pair<double, int> > q;
int st,ed;
int n,m;
int tot=0;
const int N=2000010, M=2000010;
int head[N], ver[M], Next[M], d1[N], run[N], re[N];
double edge[M];
double d[N]={};
bool v[N];
double Max=0;

void insert(int x,int y,double z)	//存图 
{
	ver[++tot]=y;//终点 
	edge[tot]=z;//权值 
	Next[tot]=head[x];
	head[x]=tot;
}

void dijkstra1() {   //堆优化的 dijkstra
	for (int i=1;i<=n;i++) d[i]=99999999.99; 
	memset(v,0,sizeof(v));
	d[st]=0.0;
	q.push(make_pair(0.0,st));
	while (q.size()) 
	{
		int x=q.top().second;
		q.pop();
		if (v[x]) continue;
		v[x]=1;
		for (int i=head[x];i;i=Next[i]) 
		{
			int y=ver[i];
			double z=edge[i];
			if (d[y]>d[x]+z) 
			{
				d[y]=d[x]+z;
				run[y]=x;  //记录经过的绿洲 
				q.push(make_pair(-d[y], y));
			}
		}
	}
}
bool operator <(rec a,rec b) 
{
    return a.t<b.t;
}
int getf(int x) 
{
    if (x==fa[x]) return x;
    return fa[x]=getf(fa[x]);
}
void init()    //初始化不能忘 
{
	memset(head,0,sizeof(head));
	memset(re,0,sizeof(re));
	memset(run,0,sizeof(run));
	memset(Next,0,sizeof(Next));
	memset(edge,0,sizeof(edge));
	memset(ver,0,sizeof(ver));
	for (int i=1;i<=n;i++) fa[i]=i;
}
int main() 
{
	while (scanf("%d %d",&n,&m)!=EOF)
	{
		init();
		Max=0;
		//读入 
   		scanf("%d %d",&st,&ed);
    	for (int i=1;i<=m;i++)
    	    scanf("%d %d %lf %lf",&k[i].x,&k[i].y,&k[i].t,&k[i].z);
    	    
		//最小生成树:Kruskal 
    	sort(k+1,k+m+1);
    	for (int i=1;i<=m;i++)
		{
    	    int x=getf(k[i].x),y=getf(k[i].y);
    	    if (x==y) continue;
    	    fa[x]=y;
    	    Max=max(Max,k[i].t);
   	     	if (getf(st)==getf(ed)) break;   //当S与T再祖先相同(在同一棵树)时,就可退出,此时Max就为最小的最大温度 
  	  	}
    	for (int i=1;i<=m;i++)  //重新构图 
    		if (k[i].t<=Max) 
    		{
				insert(k[i].x,k[i].y,k[i].z);
				insert(k[i].y,k[i].x,k[i].z);
			}
		//最小生成树:Kruskal 
		
    	dijkstra1(); 
		
		//输出 
		int kk=0; 
		for (int i=ed;i;i=run[i]) re[++kk]=i;
		while (kk>1) printf("%d ",re[kk]),kk--;
		printf("%d\n",re[1]);
    	printf("%.1lf %.1lf\n",d[ed],Max);
	}
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值