王道考研 ++++ Kruskal 克魯斯卡爾算法

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MaxSize 100
typedef struct GraphEage
{
  int front,rear,len;
  struct GraphEage *next;
}GraphEage;

int Father[MaxSize];
void InsertSort(GraphEage *G,int a,int b,int len);
int Kruskal(GraphEage *G,int n,int m);
int Find(int child);

//查找最高父節點
int Find(int child)
{
  if(Father[child] == child)return child;
  else return Find(Father[child]);
}
//插入排序
void InsertSort(GraphEage *G,int a,int b,int len)
{
  GraphEage *E,*R=G;
  E = (GraphEage*)malloc(sizeof(GraphEage));
  E->front = a;E->rear = b;E->len = len;
  E->next = NULL;
  //遍歷插入
  while (1)
  {
    if(R->next == NULL)
    { //鏈表中沒有元素或者是遍歷到最後時
      R->next = E;
      break;
    }else if(len < R->next->len)
    { //下一個元素比他大 插入
      E->next = R->next;
      R->next = E;
      break;
    }
    R = R->next;
  }
}
/*克魯斯卡爾算法*/
int Kruskal(GraphEage *G,int n,int m)
{ //ans記錄最小生成樹的邊權之和
  int ans = 0,i;
  //並查集初始化,使父節點爲自己本身
  for(i = 0;i < n;i++)Father[i] = i;
  //最小生成樹的邊數是 節點數-1
  while(n > 1)
  {
    GraphEage *R = G->next;//獲取集合中剩餘邊權最小的
    G->next = G->next->next;//在集合中刪除取出的這個元素
    //尋找這條邊兩個節點的最高父節點
    int a = Find(R->front);
    int b = Find(R->rear);
    if(a != b)//不相等說明不在一個集合中
    {
      Father[a] = b;//默認把 a 當作 b的父節點(可用秩優化)
      ans += R->len;
      n--;
    }
  }
  return ans;
}
int main(int argc, char const *argv[])
{
  GraphEage *G;
  int n,m,i;
  G = (GraphEage*)malloc(sizeof(GraphEage));
  G->next = NULL;
  printf("請輸入節點數與邊數:");
  scanf("%d%d",&n,&m);
  printf("請輸入%d條邊:\n",m);
  for(i = 0;i < m;i++)
  {
    int a,b,len;
    scanf("%d%d%d",&a,&b,&len);
    InsertSort(G,a,b,len);
  }
  int ans = Kruskal(G,n,m);
  printf("最小生成樹的路徑權值是:%d\n",ans);
  return 0;
}
// 0 1 4
// 0 4 1
// 0 5 2
// 1 2 1
// 1 5 3
// 2 3 6
// 2 5 5
// 3 4 5
// 3 5 4
// 4 5 3

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章