一、上节中的最小生成树,使用了快速排序算法;这节的最小生成树,模拟Dijkstra算法
1.既然是找一条路(最小生成树),将所有节点连接起来,那么随便选择一个顶点先,然后从这个顶点出发的边中,挑一个最短的边;然后再找一个距离这两个顶点最近的边和顶点,加入到图中,同时要避免回路;依次类推,直到加入图的顶点数 == 顶点数。
2.是不是有点像Dijkstra算法:先固定一个点,找到距离源点A最近的一个点B;然后固定点B,再找到距离B最近的点。。。
3.不同的地方就在于:Dijkstra算法是寻找的各顶点到源点的最短距离 dis[k] > dis[j] + e[j][k];最小生成树,则是寻找所有树外顶点到任一个生成树顶点的最短距离 dis[k] > e[j][k];
什么意思呢?
a. 比如现在树节点(1,2,4),非树节点(3,5,6),新加入的树节点是4(可以认为 dis[4]=0),扫描以4为初始点的边4->5,并比对 dis[5] 的值,(此时Dijkstra算法 dis[k] > dis[j] + e[j][k] = e[j][k] ),说明通过此时的树节点 4,可以使非树节点 5 到某个树节点的距离变短;
b. 更新 dis 数组,再找到非树节点中的最小值加入到树节点;
c. 继续以新加入的节点更新非树节点到树节点的距离!
二、CODE
# include <stdio.h>
int main(){
int i,j,k, t1,t2,t3;
int min,n,m;
int inf= 999999;
int book[7]={0};
int e[7][7],dis[7];
int count=0,sum=0;
scanf("%d %d", &n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
if(i==j) e[i][j]=0;
else e[i][j]=inf;
}
for(i=1;i<=m;i++){ //无向图
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
e[t2][t1]=t3;
}
for(i=1;i<=n;i++) //先将 1 加入生成树,并更新非树节点到树节点(1,)的距离
dis[i]=e[1][i];
book[1]=1;
count++;
while(count<n){
min=inf;
for(i=1;i<=n;i++){ //在非树节点中,找出最短路径
if(book[i]==0 && dis[i]<min){
min=dis[i];
j=i;
}
}
book[j]=1;
count++;
sum=sum+dis[j];
for(k=1;k<=n;k++){ //扫描当前顶点 j 的所有边,并以 j 为中间点,更新生成树到非树节点的距离
if(book[k]==0 && dis[k] >e[j][k])
dis[k]=e[j][k];
}
}
printf("%d ",sum);
getchar();return 0;
}
显然,这种方法的时间复杂度是O(N*N)。
三、堆优化查询,邻接表优化存储
dis[ ] 记录生成树到树外顶点的距离;
h[ ]是一个最小堆,以边长为准,存储的是顶点编号;
pos[ ]记录每个顶点在最小堆中的位置;
emmm,没看懂,先行记录,留作后续!
int dis[7],book[7]={0};
int h[7],pos[7],size;
void swap(int x,int y){
int t;
t=h[x];
h[x]=h[y];
h[y]=t;
t=pos[h[x]];
pos[h[x]]=pos[h[y]];
pos[h[y]] = t;
}
void siftdown(int i){
int t,flag=0;
while(i*2<=size && flag==0){
if(dis[h[i]]>dis[h[i*2]])
t=i*2;
else
t=i;
if(dis[h[t]] > dis[i*2+1])
t=2*i+1;
if(t!=i){
swap(t,i);
i=t;
}
else
flag=1;
}
}
void siftup(int i){
int flag=0;
if(i==1) return;
while(i!=1 && flag==0){
if(dis[h[i]]<dis[h[i/2]])
swap(i,i/2);
else
flag=1;
i=i/2;
}
}
int pop(){
int t;
t=h[1];
pos[t]=0;
h[1]=h[size];
pos[h[1]]=1;
size--;
siftdown(1);
return t;
}
int main(){
int n,m,i,j,k;
int u[19],v[19],w[19],first[7],next[19];
int inf=999999;
int count=0,sum=0;
scanf("%d %d",&n,&m);
for(i=1;i<=m;i++)
scanf("%d %d %d",&u[i],&v[i],&w[i]);
for(i=m+1;i<=2*m;i++){
u[i]=v[i-m];
v[i]=u[i-m];
w[i]=w[i-m];
}
for(i=1;i<=n;i++) first[i]=-1;
for(i=1;i<=2*m;i++){
next[i] = first[u[i]];
first[u[i]]=i;
}
book[1]=1;
count++;
dis[1]=0;
for(i=2;i<=n;i++) dis[i]=inf;
k=first[1];
while(k!=-1){
dis[v[k]]=w[k];
k=next[k];
}
size=n;
for(i=1;i<=size;i++) {h[i]=i; pos[i]=i;}
for(i=size/2;i>=1;i--) {siftdown(i);}
pop();
while(count<n){
j=pop();
book[j]=1;
count++;
sum=sum+dis[j];
k=first[j];
while(k!=-1){
if(book[v[k]]==0 && dis[v[k]]>w[k]){
dis[v[k]]=w[k];
siftup(pos[v[k]]);
}
k=next[k];
}
}
printf("%d ",sum);
getchar();getchar();return 0;
}