一、上节中的最小生成树,使用了快速排序算法;这节的最小生成树,模拟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)。

 

三、堆优化查询,邻接表优化存储

No.8.2 图的最小生成树(2)_dijkstra算法

 

  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;
}