题目传送门:https://www.luogu.org/problemnew/show/P4779
别人的dijstra堆优化本质是用优先队列解决的,而我,始终手写堆c选手留下了悔恨的泪水。
让我们回顾一下一般dijstra的伪代码:
for(i=1;i<=n;i++)
{
1.//找到dis[j]中最小的且j这个点没有访问过
u=j;vis[u]=1;
2.for(与u相连的所有点j)
if(dis[j]>dis[u]+w[u][j])//当然这个地方真实情况我们通常用链式前向星解决,此处方便理解
修改边;
}
那么之所以普通dijstra是一个n^2级的算法主要是因为在第一步这里我们采用一个1到n的遍历,那么如果是要求一个数组里的最小值,我们会采用线段树堆来优化,把第一步优化成一个logn级别的操作。附上代码:
#include<stdio.h>
#include<stdlib.h>
int heap[5000001]={0},mark[5000001]={0},b[5000001]={0},dis[5000001]={0},done[5000001]={0};
int n,m,s,tmp=0,size=0;
int min(int x,int y)
{
if(x>y) return y;
else return x;
}
struct d{
int w;
int st;
int ed;
int to;
}d[5000001];
void add(int x,int y,int z)
{
tmp++;
d[tmp].w=z;
d[tmp].st=x;
d[tmp].ed=y;
d[tmp].to=b[x];
b[x]=tmp;
if(x==s&&((dis[y]>z&&dis[y]!=2147483646)||dis[y]==2147483646))
{
dis[y]=z;
put(y);
}
}
int put(int x)
{
int i,j,t;
size++;
heap[size]=dis[x];
mark[size]=x;
i=size;
while(heap[i]<heap[i/2]&&i/2>0)
{
t=heap[i];heap[i]=heap[i/2];heap[i/2]=t;
t=mark[i];mark[i]=mark[i/2];mark[i/2]=t;
i=i/2;
}
return 0;
}
int get()
{
int i,j,t;
t=heap[1];heap[1]=heap[size];heap[size]=t;
t=mark[1];mark[1]=mark[size];mark[size]=t;
size--;
i=1;
while(i*2<=size&&heap[i]>min(heap[i*2],heap[i*2+1]))
{
if(heap[i*2+1]<heap[i*2]&&i*2+1<=size)
{
t=heap[i];heap[i]=heap[i*2+1];heap[i*2+1]=t;
t=mark[i];mark[i]=mark[i*2+1];mark[i*2+1]=t;
i=i*2+1;
}
else if(heap[i*2]<heap[i])
{
t=heap[i];heap[i]=heap[i*2];heap[i*2]=t;
t=mark[i];mark[i]=mark[i*2];mark[i*2]=t;
i=i*2;
}
else return 0;
}
return 0;
}
int main()
{
int i,j,x,y,z,t1,t2;
scanf("%d%d%d",&n,&m,&s);
for(i=1;i<=n;i++)
dis[i]=2147483646;
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
for(i=1;i<=n;i++)
if(i!=s)
{
put(i);
}
else
{
dis[s]=0;
put(s);
}
while(size!=0)
{
t1=heap[1];t2=mark[1];
get();
if(done[t2]==1) continue;
done[t2]=1;
for(j=b[t2];j;j=d[j].to)
if(dis[d[j].ed]>dis[t2]+d[j].w)
{
dis[d[j].ed]=dis[t2]+d[j].w;
put(d[j].ed);
}
}
for(i=1;i<=n;i++)
if(dis[i]!=2147483646)
printf("%d ",dis[i]);
else printf("2147483647 ");
return 0;
}
mark数组记录dis[x]的x,即是哪个点,这样取出之后我们也能知道这个点是哪个。