本博文源于浙江大学《数据结构》,Prim算法是今天所学的,看起来这是一个贪心算法。我们先谈这个测试案例,看博主发生了什么
这是一张带权值的有向图,老师上课用的是这张
我傻傻的试着程序,一直没发现我是有向图做的最后代码实现效果是这样子的
这个测试结果怎么看,先看0 3,0 3代表 v0 跟v3有路。
1 后面没有值代表没有边跟他连
2 5代表v2跟v5相连,这就是看测试用例输出的细节。下面还是强调一下,我给出的
7 12
2 0 4
2 5 5
0 1 2
0 3 1
1 4 10
1 3 3
3 2 2
3 5 8
3 6 4
3 4 2
4 6 6
6 5 1
我给出的是有向图的输入用例,把它改成无向图大家应该都明白的,不明的看这个博文:
(C语言)图的邻接矩阵操作集(包含测试源码)
因为老师用的是两种图操作,所以代码冗长,希望大家能理解,大家要认真看仔细每个细节,prim算法本质就是完成最小生成树的创建,最小生成树创建的指标牢记于心,下面也再放图
所以大家用这三条标准检验你的输出到底是否符合,别用脑子去检查为什么有个权值更小他不走,非要走权值最大的。当大家把定义牢记于心,并且记住贪心贪的是局部最优,那么你离理解Prim算法之路就不远了。
下面放出源代码:
//还是Prime
#include<stdio.h>
#include<stdlib.h>
#define MaxVertexNum 10
#define false 0
#define true 1
#define ERROR -1
#define INFINITY 999999
typedef int WeightType;
typedef int DataType;
typedef struct MGNode *PtrToMGNode;
typedef int bool;
typedef int Position;
typedef int ElementType;
#include<stdio.h>
#include<stdlib.h>
#define MaxVertexNum 10
#define false 0
#define true 1
#define ERROR -1
typedef int Vertex;
typedef int WeightType;
typedef int ElementType;
typedef struct LENode *PtrToLENode;
struct LENode {
Vertex V1, V2;
WeightType Weight;
};
typedef PtrToLENode LEdge;
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode {
Vertex AdjV; // 邻接点的下标
WeightType Weight;//边的权重
PtrToAdjVNode Next;
};
typedef struct Vnode{
PtrToAdjVNode FirstEdge;
DataType Data;//存顶点得数据
}AdjList[MaxVertexNum];
typedef struct GNode *PtrToGNode;
struct GNode {
int Nv;//顶点数
int Ne;//边数
AdjList G;//邻接表
};
typedef PtrToGNode LGraph;
LGraph CreateLGraph(int VertexNum)
{
Vertex V;
LGraph Graph;
Graph = (LGraph)malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
for(V = 0;V<Graph->Nv;V++){
Graph->G[V].FirstEdge = NULL;
Graph->G[V].Data = V;
}
return Graph;
}
void InsertLEdge(LGraph Graph, LEdge E)
{
PtrToAdjVNode NewNode;
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->AdjV = E->V2;
NewNode->Weight = E->Weight;
//将v2插入v1的表头
NewNode->Next = Graph->G[E->V1].FirstEdge;
Graph->G[E->V1].FirstEdge = NewNode;
}
LGraph BuildLGraph()
{
LGraph Graph;
LEdge E;
Vertex V;
int Nv,i;
scanf("%d",&Nv);//读入顶点个数
Graph = CreateLGraph(Nv);//初始化有Nv个顶点但没有边的图
scanf("%d",&(Graph->Ne));
if(Graph->Ne != 0)
{
E = (LEdge)malloc(sizeof(struct LENode));
for(i=0;i<Graph->Ne;i++)
{
scanf("%d %d %d",&E->V1,&E->V2,&E->Weight);
InsertLEdge(Graph, E);
}
}
return Graph;
}
struct MGNode {
int Nv; //一张图的顶点数
int Ne; //一张图的边数
WeightType G[MaxVertexNum][MaxVertexNum];
DataType Data[MaxVertexNum];//存顶点的数据
};
typedef PtrToMGNode MGraph;//以邻接矩阵存储的图类型
//初始化一个有VertexNum 个顶点但没有边的图
typedef int Vertex;//用顶点下标表示顶点,为整型
MGraph CreateMGraph(int VertexNum)
{
Vertex V, W;
MGraph Graph;
Graph = (MGraph)malloc(sizeof(struct MGNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
//注意:这里默认顶点编号从0开始,到(Graph->Nv-1)
for(V=0; V<Graph->Nv;V++)
for(W=0; W<Graph->Nv;W++)
Graph->G[V][W] = INFINITY;
for(int i =0;i<Graph->Nv;i++)
{
Graph->Data[i]=i;
}
return Graph;
}
typedef struct ENode *PtrToENode;
struct ENode {
Vertex V1,V2;//有向边<V1,V2>
WeightType Weight;//权值
};
typedef PtrToENode Edge;
void InsertMEdge(MGraph Graph, Edge E)
{
Graph->G[E->V1][E->V2] = E->Weight;
Graph->G[E->V2][E->V1] = E->Weight;
}
MGraph BuildMGraph()
{
MGraph Graph;
Edge E;
Vertex V;
int Nv,i;
scanf("%d",&Nv);
Graph = CreateMGraph(Nv);
scanf("%d",&(Graph->Ne));
if(Graph->Ne != 0) {
E = (Edge)malloc(sizeof(struct ENode));
for(i=0;i<Graph->Ne;i++) {
scanf("%d %d %d",&E->V1,&E->V2,&E->Weight);
InsertMEdge(Graph, E);
}
}
return Graph;
}
Vertex FindMinDist(MGraph Graph,WeightType dist[])
{
Vertex MinV,V;
WeightType MinDist = INFINITY;
for(V=0;V<Graph->Nv;V++)
if(dist[V] != 0 && dist[V] < MinDist) {
MinDist = dist[V];
MinV = V;
}
if(MinDist < INFINITY)
return MinV;
else
return -1;
}
int Prim(MGraph Graph) {
WeightType dist[MaxVertexNum],TotalWeight;
Vertex parent[MaxVertexNum],V,W;
int VCount;
LEdge E;
for(V=0;V<Graph->Nv;V++) {
dist[V] = Graph->G[0][V];
parent[V] = 0;
}
TotalWeight = 0;
VCount = 0;
LGraph MST = CreateLGraph(Graph->Nv);
E = (LEdge) malloc(sizeof(struct LENode));
dist[0] = 0;
VCount ++;
parent[0] = -1;
while(1) {
V = FindMinDist(Graph,dist);
if(V == -1)
break;
E->V1 = parent[V];
E->V2 = V;
E->Weight = dist[V];
InsertLEdge(MST,E);
TotalWeight += dist[V];
dist[V] = 0;
VCount ++;
for(W=0;W<Graph->Nv;W++)
if(dist[W] != 0 && Graph->G[V][W] < INFINITY) {
dist[W] = Graph->G[V][W];
parent[W] = V;
}
}
if(VCount < Graph->Nv)
TotalWeight = -1;
for(int i =0;i<Graph->Nv;i++)
{
PtrToAdjVNode NewNode;
NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
NewNode->Next = MST->G[i].FirstEdge;
printf("%d ",MST->G[i].Data);
NewNode = NewNode->Next;
while(NewNode != NULL)
{
printf("%d ",NewNode->AdjV);
NewNode = NewNode->Next;
}
printf("\n");
}
return TotalWeight;
}
int main()
{
MGraph Graph = BuildMGraph();
int Nv = Graph->Nv;
printf("\n\n\n\n-----List Traverse---------\n\n\n\n");
LGraph MST;
int flag = Prim(Graph);
// for(int i =0;i<Nv;i++)
// {
// PtrToAdjVNode NewNode;
// NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
// NewNode->Next = MST->G[i].FirstEdge;
// printf("%d ",MST->G[i].Data);
// NewNode = NewNode->Next;
// while(NewNode != NULL)
// {
// printf("%d ",NewNode->AdjV);
// NewNode = NewNode->Next;
// }
// printf("\n");
// }
return 0;
}