Dij:贪心思想的单源最短路,时间复杂度O(n^2)。
Dij算法流程:
- d数组记录源点s到每个点的距离,若无边则设为inf,标记源点;
- 选出d数组中未标记的最小值,该节点记为k,并标记k为已求出最短路;
- 枚举每个节点(记为j),若经过k到达j的路径<d[j]且未标记,则更新d[j];
- 重复2、3步n次;
- d[v]为s-v的最短路;
堆优Dij:即用堆优化的dij算法,时间复杂度O(nlogn);(但是据说跑起来比spfa快?求神犇解释)
堆优Dij算法流程:
- q为priority_queue,优先队列记录一个二元组,分别为索引位置和数值;
d数组记录源点s到每个点的距离,若无边则设为inf;
- 源点入队;
- 队首出队并标记队首;
- 遍历队首的邻接点,若可松弛,则更新该邻接点的最短路并将该节点压入优先队列;
不知道为什么,写出来的spfa和堆优dij的唯一区别就是spfa的队列变成了dij的优先队列,也不知道这样对不对,若有错误希望大家指出。
经测试,其实无需标记,堆优dij是照着dij模板改的,求解释。。。
#include<cstdio>
#include<cmath>
#include<queue>
#include<vector>
#include<cstring>
using namespace std; struct edge{
int to;
int w;
int next;
}; struct node{
int index,value;
node(){};
node(int x,int y){index=x;value=y;}//构造函数
friend bool operator < (node a,node b){
return a.value>b.value;
}//重载小于号
}; priority_queue<node> q;
edge e[];
int ne=,head[],d[],a[],answer[]={};
bool b[]; void add(int a,int b,int c){
e[++ne].to=b;e[ne].w=c;e[ne].next=head[a];head[a]=ne;
} void dij(int k){//k为源点编号
int i,v;
node u;
memset(d,,sizeof(d));
memset(b,,sizeof(b));//初始化
d[k]=;
//b[k]=true;
q.push(node(k,));//构造并压入源点
while(!q.empty()){
u=q.top();q.pop();//弹出队首
//if(b[u.index])continue;
//b[u.index]=true;//标记
for(i=head[u.index];i!=-;i=e[i].next){//遍历邻接点
v=e[i].to;
if(u.value+e[i].w<d[v]/*&&b[v]==false*/){
d[v]=u.value+e[i].w;//松弛操作
q.push(node(v,d[v]));//压入新节点
}
}
}
} int main(){
int n,p,c,ans=,i,j,u,v,w;
memset(head,-,sizeof(head));
memset(e,,sizeof(e));
scanf("%d%d%d",&n,&p,&c);
for(i=;i<=n;i++)scanf("%d",&a[i]);
for(i=;i<=c;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);//连边
}
for(i=;i<=p;i++){
dij(i);
int sum=;
for(j=;j<=n;j++)sum+=d[a[j]];
ans=min(ans,sum);
}
printf("%d\n",ans);
}