K氏法
K氏法也叫Kruskal算法,是将各边按照权值从小到大排列,接着从权值最低的边开始建立最小成本生成树,如果加入的边造成了贿赂,则舍弃不用,直到加入n-1个边为止。
示例
把所有边的成本列出,按照从小到大排列。
起始 | 终止 | 成本 |
B | C | 3 |
B | D | 5 |
A | B | 6 |
C | D | 7 |
B | F | 8 |
D | E | 9 |
A | E | 10 |
D | F | 11 |
A | F | 12 |
E | F | 16 |
1.选择成本最低的一条边作为建立最小成本生成树的起点。
B----C 3
2.按照建立的表格,按序加入边
B-----C 3 B----D 5
直到完成所有的生成树,结果为:
代码:
public class Node { const int MAXLENGTH = 20; //链表的最大长度 public int[] from = new int[MAXLENGTH]; public int[] to = new int[MAXLENGTH]; public int[] find = new int[MAXLENGTH]; public int[] val = new int[MAXLENGTH]; public int[] next = new int[MAXLENGTH]; //链表的一个节点位置 public Node() { for(int i = 0; i < MAXLENGTH; i++) { next[i] = -2; //-2表示未用节点 } } //查找可用节点 public int FindFree() { int i; for(i = 0; i < MAXLENGTH; i++) { if (next[i] == -2) break; } return i; } //建立链表 public void Create(int header,int freeNode,int dataNum,int fromNum,int toNum,int findNum) { int point; //现在的节点位置 if (header == freeNode) //新的链表 { val[header] = dataNum; //设置数据编号 from[header] = fromNum; find[header] = findNum; to[header] = toNum; next[header] = -1; //将下个节点的位置 ,-1表示空节点 } else { point = header; val[freeNode] = dataNum; from[freeNode] = fromNum; find[freeNode] = findNum; to[freeNode] = toNum; //设置数据名称 next[freeNode] = -1; //寻找链表的尾端 while (next[point] != -1) { point = next[point]; } //将新节点串联在原链表的尾端 next[point] = freeNode; } } public void Print(int header) { int point; point = header; while (point != -1) { Console.Write($"起始顶点 [{from[point]}] 终止顶点["); Console.Write($"{to[point]} ] 路径长度[{val[point]}]"); Console.WriteLine(); point = next[point]; } } }
class Program { static int verts = 6; static int[] v = new int[verts + 1]; static Node newlist = new Node(); static void Main(string[] args) { int[,] data = { { 1, 2, 6 }, { 1, 6, 12 }, { 1, 5, 10 }, { 2, 3, 3 }, { 2, 4, 5 }, { 2, 6, 8 }, { 3, 4, 7 }, { 4, 6, 11 }, { 4, 5, 9 }, { 5, 6, 16 } }; int dataNum; int fromNum; int toNum; int findNum; int header = 0; int freeNode; for(int i = 0; i < 10; i++) { for(int j = 1; j <= verts; j++) { if (data[i, 0] == j) { fromNum = data[i, 0]; toNum = data[i, 1]; dataNum = data[i, 2]; findNum = 0; freeNode = newlist.FindFree(); newlist.Create(header, freeNode, dataNum, fromNum, toNum, findNum); } } } newlist.Print(header); Console.WriteLine("建立最小成本的生成树:"); MinTree(); Console.ReadLine(); } //找出剩下最小的 static int FindMinCost() { int minVal = 100; int retPtr = 0; int a = 0; while (newlist.next[a] != -1) { if (newlist.val[a] < minVal && newlist.find[a] == 0) { minVal = newlist.val[a]; retPtr = a; } a++; } newlist.find[retPtr] = 1; return retPtr; } static void MinTree() { int result = 0; int mcePtr; int a = 0; for(int i = 0; i <= verts; i++) { v[i] = 0; } while (newlist.next[a] != -1) //next表示的是有几条边 { mcePtr = FindMinCost(); v[newlist.from[mcePtr]]++; v[newlist.to[mcePtr]]++; if (v[newlist.from[mcePtr]] > 1 && v[newlist.to[mcePtr]] > 1) { v[newlist.from[mcePtr]]--; v[newlist.to[mcePtr]]--; result = 1; } else result = 0; if (result == 0) { Console.Write($"起始顶点[{newlist.from[mcePtr]}] 终止顶点[{newlist.to[mcePtr]}] 路径长度[{newlist.val[mcePtr]}"); Console.WriteLine(); } a++; } } }