(堆优化的最短路)
题意: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); } }