求某个顶点的最短路径生成树,且边的总权值最小。如果有多个,输出任意一个即可。(输出最小权值以及所选的边)
选边的时候注意一下:如果u到v,与u到k到v的路径长度相同。应当选取后者。即尽可能经过多的顶点,这样可以保证总权值最小。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define N 300005
#define inf 0x3f3f3f3f3f3f3f3f
struct Edge{
int to,next,id;
LL w;
}edge[N<<1];
int cnt,n,head[N],pre[N];
LL low[N],w[N];
bool vis[N];
inline void add(int u,int v,LL w,int id){
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
edge[cnt].id=id;
head[u]=cnt++;
}
void spfa(int s)
{
int i,j;
memset(vis,0,sizeof(vis));
vis[s]=1,low[s]=0;
queue<int> q;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=0;
for(i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(low[v]>low[u]+edge[i].w){
low[v]=low[u]+edge[i].w;
pre[v]=edge[i].id;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
else if(low[v]==low[u]+edge[i].w){
if(w[pre[v]]>edge[i].w){
pre[v]=edge[i].id;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
}
}
int main()
{
int m,i,u;
scanf("%d%d",&n,&m);
memset(low,inf,sizeof(low));
memset(head,-1,sizeof(head));
for(i=1;i<=m;++i){
int x,y;
LL z;
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z,i);
add(y,x,z,i);
w[i]=z;
}
scanf("%d",&u);
spfa(u);
LL s=0;
for(i=1;i<=n;++i) if(pre[i]) s+=w[pre[i]];
printf("%lld\n",s);
for(i=1;i<=n;++i) if(pre[i]) printf("%d ",pre[i]);
puts("");
return 0;
}