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 N, M (1 ≤ N, M ≤ 105).
Then followed by M lines, each line contains four integers Xi, Yi, Di, Ci (0 ≤ Xi, Yi < N, 0 < Di, Ci < 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
分析:要求:求0点到所有点的最短时间和建路最小花费。时间优先权大于花费。0到所有点的最短时间就是单源点最小权,可以用dijkstra做。建路花费最小可以这么做:对于某个点保存其他点到他的最小花费,最累加求和。
第一次用优先队列优化dijkstra,做了好久。
比较: 一般的dijkstar就是直接对边松弛操作。而用优先队列做,每次可以直接取到权值最小的边。
优先队列的大致思想:先用 edges保存边的信息,在用G[]保留每个点链接的边在edges中的位置,这样松弛操作不在需要遍历。
用结构体将 点编号,权值(起点到该点)链接在一起,重载优先权。先把点放入队列,然后取到最小权值进行边的松弛操作……。具体代码中有注释。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll INF=1e15;
int n,m,x1,x;
ll x2,x3;
const int maxn=1e5+5;
struct Edge //保存边(对边编号)
{
int from,to,dist,dist2;
Edge(int from,int to,int dist,int dist2):from(from),to(to),dist(dist),dist2(dist2) {}
};
struct Node //重载优先队列的优先
{
int d; //编号 时间 花费
ll c,tt;
bool operator < (const Node& rhs) const {
return c>rhs.c; //升序和平常相反
}
};
vector edges; //保留边的信息
vector<int> G[maxn]; //保存点链接的边的信息
bool done[maxn];
ll d1[maxn],d2[maxn];
void init()
{
for(int i=0;ivoid AddEdge(int from,int to,int dist,int dist2)
{
edges.push_back(Edge(from,to,dist,dist2));
edges.push_back(Edge(to,from,dist,dist2));
int mm=edges.size();
G[to].push_back(mm-1); //和 to相邻的边在 edges[]中的位置
G[from].push_back(mm-2); //和from相邻的边在 edges[]中的位置
}
void dijkstra()
{
priority_queue Q;
for(int i=0;i//时间 花费
d1[0]=0,d2[0]=0;
memset(done,false,sizeof(done));
Q.push((Node){0,0,0});
while(!Q.empty())
{
Node x=Q.top();
Q.pop();
int u=x.d;
if(done[u])
continue;
done[u]=true;
for(int i=0;i// 对于点x找它的链接边信息 进行松弛操作
{
Edge& e=edges[G[u][i]];
if(d1[e.to]>d1[u]+e.dist)
{
d1[e.to]=d1[u]+e.dist;
d2[e.to]=e.dist2;
Q.push((Node){e.to,d1[e.to],d2[e.to]});
}
else if(d1[u]+e.dist==d1[e.to]&&e.dist2int main()
{
int t;
cin>>t;
while(t--)
{
ll sum1=0,sum2=0;
cin>>n>>m;
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%lld%lld",&x,&x1,&x2,&x3);
AddEdge(x,x1,x2,x3);
}
dijkstra();
for(int i=1;iprintf("%lld %lld\n",sum1,sum2);
}
return 0;
}