Highway Project 浙江省第十三届省赛K题 ZOJ 3946(dijkstra+邻接表+优先队列)

Highway Project

Time Limit: 2 Seconds       Memory Limit: 65536 KB

Edward, the emperor of the Marjar Empire, wants to build some bidirectional highways so that he can reach other cities from the capital as fast as possible. Thus, he proposed the highway project.

The Marjar Empire has N cities (including the capital), indexed from 0 to N - 1 (the capital is 0) and there are M highways can be built. Building the i-th highway costs Ci dollars. It takes Di minutes to travel between city Xi and Yi on the i-th highway.

Edward wants to find a construction plan with minimal total time needed to reach other cities from the capital, i.e. the sum of minimal time needed to travel from the capital to city i (1 ≤ i ≤ N). Among all feasible plans, Edward wants to select the plan with minimal cost. Please help him to finish this task.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first contains two integers NM (1 ≤ NM ≤ 105).

Then followed by M lines, each line contains four integers XiYiDiCi (0 ≤ XiYi < N, 0 < DiCi < 105).

Output

For each test case, output two integers indicating the minimal total time and the minimal cost for the highway project when the total time is minimized.

Sample Input
2
4 5
0 3 1 1
0 1 1 1
0 2 10 10
2 1 1 1
2 3 1 2
4 5
0 3 1 1
0 1 1 1
0 2 10 10
2 1 2 1
2 3 1 2
Sample Output
4 3
4 4

Author:  Lu, Yi

Source: The 13th Zhejiang Provincial Collegiate Programming Contest


题意:给出n个点和m条线路,每条线路有起点终点,花费时间(因为习惯,我下面说成距离)和费用。求源点到各个点之间的最短距离之和在最短距离情况下的最少花费。

思路:首先,由于点的数量达到了1e5,所以只能用邻接表存数据。其次就是迪杰斯特拉算法,从小到大求出从源点到各个点的最短路(具体算法我博客里有),由于时间限制,需要用优先队列优化。代码如下:

#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<cstring>
#define MAXN 100009
using namespace std;
struct node1{//加入优先队列的结点 
	bool friend operator<(node1 a,node1 b){
		return a.distance>b.distance;
	}//重载运算符,使队列中distance小的先出队列 
	int start;//当前点 
	long long distance;
};
struct node2{//储存点的信息 
	int point;
	int d;//距离 
	int c;//费用 
};
vector<node2>graph[MAXN];//邻接表存图 
bool final[MAXN];//代表 
int  money[MAXN];//连通到某个点的费用 
long long dis[MAXN];//从源点到每个点的距离 
void myinit(){//初始化 
	memset(final,0,sizeof(final));
	memset(money,0,sizeof(money));
	for(int i=0;i<MAXN;i++){
		graph[i].clear();
		dis[i]=1e15;
	}
}
void dijkstra(int st){
	priority_queue<node1>q;//优先队列存储当前连接的点 
	dis[st]=0;
	node1 e1;
	e1.start=st;e1.distance=dis[st];
	q.push(e1);
	while(!q.empty()){
		node1 e2=q.top();//出优先队列的为当前从源点出发最短的点 
		q.pop();
		int now=e2.start;
		if(final[now]==1)continue;//如果出队列的点之前已经被加入已找到的集合,则进行下一循环 
		final[now]=1;//将当前点设为已找到 
		for(int i=0;i<graph[now].size();i++){//遍历每个点的邻接点 找通过当前的now点到该点路径小于原来找到的路径的点 
			if(!final[graph[now][i].point] && (dis[now]+graph[now][i].d<=dis[graph[now][i].point])){
				if(dis[now]+graph[now][i].d==dis[graph[now][i].point])//如果两种方式路径长度相同,则取费用少的 
				money[graph[now][i].point]=min(graph[now][i].c,money[graph[now][i].point]);
				else 
				money[graph[now][i].point]=graph[now][i].c;//取路径长度短的 
				dis[graph[now][i].point]=dis[now]+graph[now][i].d;
				node1 e3;
				e3.start=graph[now][i].point;e3.distance=dis[graph[now][i].point];
				q.push(e3);//加入优先队列 
			}
		}
	}
}
int main(){
	int cases,i,n,m,x,y,dd,cc;
	cin>>cases;
	while(cases--){
		scanf("%d%d",&n,&m);
		myinit();
		for(i=1;i<=m;i++){
			scanf("%d%d%d%d",&x,&y,&dd,&cc);
			node2 n1,n2;
			n1.point=y;n1.d=dd;n1.c=cc;
			n2.point=x;n2.d=dd;n2.c=cc;
			graph[x].push_back(n1);//构建图的邻接表 
			graph[y].push_back(n2);
		}
		dijkstra(0);//迪杰斯特拉求最短路 
		long long ans1,ans2;
		ans1=0;ans2=0;
		for(i=0;i<n;i++){
		    ans1+=dis[i];//从源点到各个点的距离 
			ans2+=money[i];//从原点连通到该点的费用 
		}
		cout<<ans1<<" ";
		cout<<ans2<<endl;
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值