csu2161: 漫漫上学路(Hash+最短路)

2161: 漫漫上学路

Submit Page    Summary    Time Limit: 2 Sec     Memory Limit: 128 Mb     Submitted: 26     Solved: 9    


Description

众所周知,CSU(CaliforniaCSU(California StateState University)University) 的上课地点距离学生公寓很远,对于爱睡懒觉的小Z来说,每天去上课就成了一件非常头疼的事,如果有早课的话更是如此。为了能让自己多睡一会,同时不至于上课迟到,小Z决定规划一条去新校的路线。

去新校的路上有很多条双向道路,每条道路连接了两个路口,且直接连接两个路口的道路只有一条,不存在一条道路的两端为同一个路口,每条道路都有一定的距离。同时道路两侧商铺众多,在提供了美食的同时也造成了一定程度的拥堵,在小Z心中每条道路都有一个拥堵值和美味值,且定义某条从学生公寓路口到新校路口的路线的拥堵值为其经过的道路的拥堵值之和,美味值为其经过道路的美味值之和。

因为起得晚,所以小Z没法去食堂买早餐,只能够顺路购买。小Z希望找到一条去新校最短的路线,如果存在多条总距离最短的路线,输出拥堵值最小的路线,如果拥堵值仍然相同,输出美味值最大的那条线路(小Z是个爱学习的好孩子,为了上课不迟到,有时只能狠心不吃美味的早餐了┭┮﹏┭┮)

Input

第一行为一个正整数 TT ,代表数据组数(不超过 1515 组)

第二行为两个正整数 n,mn,m ,代表路口数和道路数( 1≤n≤1000,n−1≤m≤n(n−1)/21≤n≤1000,n−1≤m≤n(n−1)/2)

其中 11 代表学生公寓路口, nn 代表新校路口

之后 mm 行,每行 55 个数 u,v,x,y,zu,v,x,y,z

u,vu,v 代表这条道路连接的两个路口,

xx 代表这条道路的长度(1≤x≤10001≤x≤1000 ),

yy 代表这条道路的拥堵值(0≤y≤10000≤y≤1000 ),

zz 代表这条道路的美味值(0≤z≤10000≤z≤1000 )。

Output

第一行输出三个正整数 r1,r2,r3r1,r2,r3 ,代表符合题意最优的那条路径的总距离,拥堵值和美味值

(数据保证总距离最小、拥堵值最小、美味值最大的路径是存在且唯一的)

接着顺序输出路径上经过的地点(以 11 开头,以 nn 结束)

具体参见样例

Sample Input

1
4 6
1 2 1 3 5
2 4 2 2 0
1 4 3 6 2
2 3 4 5 3
1 3 1 2 4
3 4 2 3 2

Sample Output

3 5 6
1 3 4

Hint

Source

Author

周杰辉

题意不难理解,就不多做赘述了。

思路:考虑到路线的选择上,尽可能短的路程是最重要,尽可能小的拥堵值是次要的,尽可能大的美食值是最不重要的,因此我们不难想到哈希的思想,把这三个数据压缩入同一个值中使之为:长度*1000000000000+拥堵值*1000000-美味值(选择这些数值是因为拥堵和美味值的和上限都是1000000),与此同时,为了防止美味值影响到拥堵值,我们要把初始的长度设置为999999(1000000会影响到拥堵值),然后据此跑出最短路即可。

AC代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int size=1e3+5;
const long long inf=2e18;
typedef long long LL;
struct Edge{
	int u,v;long long w;
	Edge(){}
	Edge(int u,int v,long long  w):u(u),v(v),w(w){}
}; 
struct node{
	int id;long long w;
	node(){}
	node(int id,long long w):id(id),w(w){} 
	friend bool operator<(node a,node b)
	{
		return a.w>b.w;
	}
};
priority_queue<node> q;
vector<Edge> edge[size];
long long  dis[size];int vis[size];
int pre[size];int ans[size*size];
void Dijkstra(int beg)
{
	memset(vis,0,sizeof(vis));
	while(!q.empty()) q.pop();
	q.push(node(beg,999999)),dis[beg]=999999;
	while(!q.empty())
	{
		node s=q.top();
		q.pop();
		int id=s.id;
		if(dis[id]!=s.w) continue;
		for(int i=0;i<edge[id].size();i++)
		{
			if(dis[edge[id][i].v]>dis[id]+edge[id][i].w)
			{
				pre[edge[id][i].v]=id;
				dis[edge[id][i].v]=dis[id]+edge[id][i].w;
				q.push(node(edge[id][i].v,dis[edge[id][i].v]));
			}
		}
	}
}
int main()
{
	int n,m;
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) edge[i].clear(),dis[i]=inf;
		for(int i=0;i<m;i++)
		{
			int u,v;LL x,y,z;
			scanf("%d%d%lld%lld%lld",&u,&v,&x,&y,&z);
			LL real=x*1000000000000+y*1000000-z;
			edge[u].push_back(Edge(u,v,real));
			edge[v].push_back(Edge(v,u,real));
		}
		Dijkstra(1);
		LL a,b,c;
		a=dis[n]/1000000000000;
		b=dis[n]%1000000000000/1000000;
		c=dis[n]%1000000;
		long long cnt=0;
		for(int i=n;i!=1;i=pre[i])
		{
			ans[cnt++]=i;
		}
		ans[cnt++]=1;
		c=999999-c;
		printf("%lld %lld %lld\n",a,b,c);
		for(int i=cnt-1;i>=0;i--)
		{
			printf("%d",ans[i]);
			if(i!=0) printf(" ");
			else printf("\n");
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值