1. 程式人生 > >51nod 1443 路徑和樹(最短路樹)

51nod 1443 路徑和樹(最短路樹)

題目連結:路徑和樹

題意:給定無向帶權連通圖,求從u開始邊權和最小的最短路樹,輸出最小邊權和。

題解:構造出最短路樹,把存留下來的邊權全部加起來。(跑dijkstra的時候鬆弛加上$ < $變成$ <= $,因為之後跑到該頂點說明是傳遞下來的,該情況邊權和最小。)

以樣例作說明:第一次從頂點3跑到頂點1,最短路為2;第二次從頂點3經過頂點2跑到頂點1,最短路也為2,但是第二次跑的方式可以把從頂點3跑到頂點2的包括進去,這樣形成的最短路樹邊權和最小。

 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\n",ans); 93 return 0; 94 }
Code