堆优DIJ模板
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模板改的,求解释。。。
1 #include<cstdio> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstring> 6 using namespace std; 7 8 struct edge{ 9 int to; 10 int w; 11 int next; 12 }; 13 14 struct node{ 15 int index,value; 16 node(){}; 17 node(int x,int y){index=x;value=y;}//构造函数 18 friend bool operator < (node a,node b){ 19 return a.value>b.value; 20 }//重载小于号 21 }; 22 23 priority_queue<node> q; 24 edge e[10000]; 25 int ne=0,head[1000],d[1000],a[1000],answer[1000]={0}; 26 bool b[1000]; 27 28 void add(int a,int b,int c){ 29 e[++ne].to=b;e[ne].w=c;e[ne].next=head[a];head[a]=ne; 30 } 31 32 void dij(int k){//k为源点编号 33 int i,v; 34 node u; 35 memset(d,127,sizeof(d)); 36 memset(b,0,sizeof(b));//初始化 37 d[k]=0; 38 //b[k]=true; 39 q.push(node(k,0));//构造并压入源点 40 while(!q.empty()){ 41 u=q.top();q.pop();//弹出队首 42 //if(b[u.index])continue; 43 //b[u.index]=true;//标记 44 for(i=head[u.index];i!=-1;i=e[i].next){//遍历邻接点 45 v=e[i].to; 46 if(u.value+e[i].w<d[v]/*&&b[v]==false*/){ 47 d[v]=u.value+e[i].w;//松弛操作 48 q.push(node(v,d[v]));//压入新节点 49 } 50 } 51 } 52 } 53 54 int main(){ 55 int n,p,c,ans=999999999,i,j,u,v,w; 56 memset(head,-1,sizeof(head)); 57 memset(e,0,sizeof(e)); 58 scanf("%d%d%d",&n,&p,&c); 59 for(i=1;i<=n;i++)scanf("%d",&a[i]); 60 for(i=1;i<=c;i++){ 61 scanf("%d%d%d",&u,&v,&w); 62 add(u,v,w); 63 add(v,u,w);//连边 64 } 65 for(i=1;i<=p;i++){ 66 dij(i); 67 int sum=0; 68 for(j=1;j<=n;j++)sum+=d[a[j]]; 69 ans=min(ans,sum); 70 } 71 printf("%d\n",ans); 72 }