题目链接:路径和树
题意:给定无向带权连通图,求从u开始边权和最小的最短路树,输出最小边权和。
题解:构造出最短路树,把存留下来的边权全部加起来。(跑dijkstra的时候松弛加上$ < $变成$ <= $,因为之后跑到该顶点说明是传递下来的,该情况边权和最小。)
以样例作说明:第一次从顶点3跑到顶点1,最短路为2;第二次从顶点3经过顶点2跑到顶点1,最短路也为2,但是第二次跑的方式可以把从顶点3跑到顶点2的包括进去,这样形成的最短路树边权和最小。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <queue> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 typedef long long ll; 9 const int N=3e5+10; 10 11 struct qnode{ 12 ll v,w; 13 qnode(){} 14 qnode(ll v,ll w):v(v),w(w){} 15 bool operator < (const qnode& b) const{ 16 return w>b.w; 17 } 18 }; 19 20 struct node{ 21 ll nxt,v,w; 22 node(){} 23 node(ll nxt,ll v,ll w):nxt(nxt),v(v),w(w){} 24 }; 25 26 ll n,m,tot,ans=0; 27 node edge[N<<1]; 28 ll head[N],d[N],w[N]; 29 qnode cur,tmp; 30 bool vis[N]; 31 priority_queue <qnode> Q; 32 pair <ll,ll> fa[N]; 33 vector <ll> g[N]; 34 35 void add_edge(ll u,ll v,ll w){ 36 edge[tot]=node(head[u],v,w); 37 head[u]=tot++; 38 } 39 40 void init(){ 41 tot=1; 42 memset(head,0,sizeof(head)); 43 } 44 45 void dijkstra(ll s){ 46 memset(vis,0,sizeof(vis)); 47 for(int i=0;i<N;i++) d[i]=1e18; 48 d[s]=0; 49 Q.push(qnode(s,0)); 50 while(!Q.empty()){ 51 cur=Q.top(); 52 Q.pop(); 53 ll u=cur.v; 54 if(vis[u]) continue; 55 vis[u]=true; 56 for(ll i=head[u];i;i=edge[i].nxt){ 57 ll v=edge[i].v; 58 ll w=edge[i].w; 59 if(d[u]+w<=d[v]){ 60 d[v]=d[u]+w; 61 fa[v]=make_pair(u,(i+1)/2); 62 Q.push(qnode(v,d[v])); 63 } 64 } 65 } 66 } 67 68 void dfs(ll u,ll father){ 69 for(ll v:g[u]){ 70 if(v!=father) dfs(v,u); 71 } 72 ans+=w[fa[u].second]; 73 } 74 75 int main(){ 76 init(); 77 scanf("%lld%lld",&n,&m); 78 for(int i=1;i<=m;i++){ 79 ll u,v; 80 scanf("%lld%lld%lld",&u,&v,&w[i]); 81 add_edge(u,v,w[i]); 82 add_edge(v,u,w[i]); 83 } 84 ll st; 85 scanf("%lld",&st); 86 dijkstra(st); 87 for(ll i=1;i<=n;i++){ 88 if(st==i) continue; 89 g[fa[i].first].push_back(i); 90 } 91 dfs(st,0); 92 printf("%lld ",ans); 93 return 0; 94 }