51nod 1443 路径和树(最短路树)

时间:2021-08-09 09:42:26

题目链接:路径和树

题意:给定无向带权连通图,求从u开始边权和最小的最短路树,输出最小边权和。

题解:构造出最短路树,把存留下来的边权全部加起来。(跑dijkstra的时候松弛加上$ < $变成$ <= $,因为之后跑到该顶点说明是传递下来的,该情况边权和最小。)

以样例作说明:第一次从顶点3跑到顶点1,最短路为2;第二次从顶点3经过顶点2跑到顶点1,最短路也为2,但是第二次跑的方式可以把从顶点3跑到顶点2的包括进去,这样形成的最短路树边权和最小。

 #include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long ll;
const int N=3e5+; struct qnode{
ll v,w;
qnode(){}
qnode(ll v,ll w):v(v),w(w){}
bool operator < (const qnode& b) const{
return w>b.w;
}
}; struct node{
ll nxt,v,w;
node(){}
node(ll nxt,ll v,ll w):nxt(nxt),v(v),w(w){}
}; ll n,m,tot,ans=;
node edge[N<<];
ll head[N],d[N],w[N];
qnode cur,tmp;
bool vis[N];
priority_queue <qnode> Q;
pair <ll,ll> fa[N];
vector <ll> g[N]; void add_edge(ll u,ll v,ll w){
edge[tot]=node(head[u],v,w);
head[u]=tot++;
} void init(){
tot=;
memset(head,,sizeof(head));
} void dijkstra(ll s){
memset(vis,,sizeof(vis));
for(int i=;i<N;i++) d[i]=1e18;
d[s]=;
Q.push(qnode(s,));
while(!Q.empty()){
cur=Q.top();
Q.pop();
ll u=cur.v;
if(vis[u]) continue;
vis[u]=true;
for(ll i=head[u];i;i=edge[i].nxt){
ll v=edge[i].v;
ll w=edge[i].w;
if(d[u]+w<=d[v]){
d[v]=d[u]+w;
fa[v]=make_pair(u,(i+)/);
Q.push(qnode(v,d[v]));
}
}
}
} void dfs(ll u,ll father){
for(ll v:g[u]){
if(v!=father) dfs(v,u);
}
ans+=w[fa[u].second];
} int main(){
init();
scanf("%lld%lld",&n,&m);
for(int i=;i<=m;i++){
ll u,v;
scanf("%lld%lld%lld",&u,&v,&w[i]);
add_edge(u,v,w[i]);
add_edge(v,u,w[i]);
}
ll st;
scanf("%lld",&st);
dijkstra(st);
for(ll i=;i<=n;i++){
if(st==i) continue;
g[fa[i].first].push_back(i);
}
dfs(st,);
printf("%lld\n",ans);
return ;
}