题意:t组测试样例,每组样例先给出一行n m (表示0~n-1个点,m条边)随后给出m行边的信息,每行给出u , v ,t ,w (表示从u到v需要消耗t的时间和w的费用修路),问你每次都从0点开始去完所有点需要的最小时间是多少和所需要的修路费用,若是有多种答案输出修路费用最少的一组。
题解:(一开始没看样例又都错题,傻傻的看成了最小生成树了orz)因为它求的是每次从起点0出发一次去一个点,去完所有点的总时间,明显就是最短路(时间1e5不能暴力直接上一波模板)求最小时间,至于修路的费用,我们只需要把它加多一个条件(选取下一个要到达的点时在时间相同下先选修路费用最少的,改动一下优先队列比较即可)。
代码如下:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define ll long long
const int maxn = 1e5 + 500;
struct edge{//存边用于建图
int v;
ll t, w;
edge() {}
edge(int vv,ll tt, ll ww){
v = vv;
t = tt;
w = ww;
}
};
struct node{//存点用与优先队列
int i;
ll t, w; //i=当前点,t=起点到当前点的最短时间,w=起点所在集合要到i点消耗的费用
node() {}
node( int ii,ll tt, ll ww){
i = ii;
t = tt;
w = ww;
}
bool operator <(const node &a)const{//按时间从小到大排,相同按费用小到大排
if (a.t != t)
return a.t < t;
return a.w < w;
}
};
vector<edge>g[maxn];
bool vis[maxn];
ll dis[maxn];
int n, m;
void init() {
for (int i = 0; i <= n; i++)
g[i].clear(), vis[i] = false;
}
ll dijsktra(int s){//s为起点
ll sum = 0;
priority_queue<node>q;
q.push(node(s, 0, 0));
while (!q.empty()){
node p = q.top();
q.pop();
if (vis[p.i]) continue; //访问过跳过
dis[p.i] = p.t; //可以存到各个点的最短时间
sum += p.w;
vis[p.i] = true;
for (int i = 0; i < g[p.i].size(); i++)
{
edge &e = g[p.i][i];
if (vis[e.v]) continue;
q.push(node(e.v, p.t + e.t, e.w));
}
}
return sum;
}
int main(){
int T, uu, vv;
ll tt, ww;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
init();
while (m--)
{
scanf("%d%d%lld%lld", &uu, &vv, &tt, &ww);
g[uu].push_back(edge(vv, tt, ww));
g[vv].push_back(edge(uu, tt, ww));
}
ll ans2 = dijsktra(0);
ll ans1 = 0;
for (int i = 1; i < n; i++)
ans1 += dis[i];
printf("%lld %lld\n", ans1, ans2);
}
}