很明显聪明的同学已经发现,这是一个稠密图,所以用邻接矩阵。可以很好的表达,比邻接表有优势,所以,采用邻接矩阵破题,
很明显,这是一个最小生成树问题,也可以认为贪心算法,接下来我将分别展示两个实现路径,第一个 prim 算法, 第二个kruskal算法(等等)。
第一个 prim 算法,真是,咋又出问题了,鲁棒性也太差了。
测试点 提示 内存(KB) 用时(ms) 结果 得分 0 sample换数字,各种回路判断 364 1 答案正确
15 / 15 1 M<N-1,不可能有生成树 176 1 答案正确
2 / 2 2 M达到N-1,但是图不连通 344 1 答案正确
2 / 2 3 最大N和M,连通 4272 7 答案错误
0 / 5 4 最大N和M,不连通 4088 5 答案正确
6 / 6
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式:
输入数据包括城镇数目正整数 n(≤1000)和候选道路数目 m(≤3n);随后的 m 行对应 m 条道路,每行给出 3 个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从 1 到 n 编号。
输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出 −1,表示需要建设更多公路。
输入样例:
6 15 1 2 5 1 3 3 1 4 7 1 5 4 1 6 2 2 3 4 2 4 6 2 5 2 2 6 6 3 4 6 3 5 1 3 6 1 4 5 10 4 6 8 5 6 3
输出样例:
12
第一个 prim 算法,我的AC:
采用了,最小堆 + prim,.
#include<stdio.h> #include<stdlib.h> #include<stdbool.h> #define MaxVertex 1001 #define INFITY 100001 #define MinValue -1 typedef struct ENode *Edge; struct ENode{ int V1, V2; int Weight; }; typedef struct GNode *MGraph; struct GNode{ int Nv; int Ne; int G[MaxVertex][MaxVertex]; }; typedef struct Sign_Dist_VNode DistNode; struct Sign_Dist_VNode{ int V; int Weight; }; typedef struct Heap *MinHeap; struct Heap{ DistNode *Data; int Size; }; MGraph Build_Graph(); MGraph Init_Graph(); void Insert_Graph(MGraph M, Edge E); MinHeap Init_Heap(int N); void Creat_Heap(MGraph M, MinHeap H, int Vertex, bool* Visited, bool *collected); void Push_Heap(MinHeap H, int index, int Weight, bool *collected); void Counterpoise_Heap(MinHeap H, int index, int V, int Weight); bool IsEmpty_Heap(MinHeap H); DistNode Pop_Heap(MinHeap H, bool *collected); void Prim(MGraph M, MinHeap H, bool* Visited, int *dist); void Print_Result(int N, int *dist, bool* Visited); int main() { MGraph M; MinHeap H; int *dist; bool *Visited; M = Build_Graph(); H = Init_Heap(M ->Nv); dist = (int*)malloc(sizeof(int) * M ->Nv); Visited = (bool*)calloc(M ->Nv, sizeof(bool)); Prim(M, H, Visited, dist); Print_Result(M ->Nv, dist, Visited); return 0; } void Prim(MGraph M, MinHeap H, bool* Visited, int *dist) { int j; bool *collected; collected = (bool*)calloc(M ->Nv, sizeof(bool)); for(j = 0; j < M ->Nv; j++){ dist[j] = INFITY; } DistNode Data; Creat_Heap(M, H, 0, Visited, collected); Visited[0] = true; dist[0] = 0; while(Data = Pop_Heap(H, collected), Data.Weight > 0){ if(!Visited[Data.V] && dist[Data.V] > Data.Weight){ dist[Data.V] = Data.Weight; } Visited[Data.V] = true; for(j = 0; j < M ->Nv; j++){ if(!Visited[j] && M ->G[Data.V][j] < INFITY && (dist[j] > dist[Data.V] + M ->G[Data.V][j])){ dist[j] = M ->G[Data.V][j]; Push_Heap(H, j, dist[j], collected); //有人会问,这样不会产生数据重复吗,注意Visited,遵循一次访问原则。 } } } } void Print_Result(int N, int *dist, bool* Visited) { int i, cost = 0; for(i = 0; i < N; i++){ if(!Visited[i]){ printf("-1\n"); return ; } cost += dist[i]; } printf("%d\n", cost); return ; } MGraph Build_Graph() { MGraph M; Edge E; M = Init_Graph(); E = (Edge)malloc(sizeof(struct ENode)); for(int i = 0; i < M ->Ne; i++){ scanf("%d %d %d", &E ->V1, &E ->V2, &E ->Weight); E ->V1 --; E ->V2 --; Insert_Graph(M, E); } return M; } MGraph Init_Graph() { MGraph M; M = (MGraph)malloc(sizeof(struct GNode)); scanf("%d %d", &M ->Nv, &M ->Ne); for(int i = 0; i < (M ->Nv); i++){ for(int j = 0; j < (M ->Nv); j++){ M ->G[i][j] = INFITY; } } return M; } void Insert_Graph(MGraph M, Edge E) { M ->G[E ->V1][E ->V2] = E ->Weight; M ->G[E ->V2][E ->V1] = E ->Weight; } void Creat_Heap(MGraph M, MinHeap H, int Vertex, bool* Visited, bool *collected) { for(int j = 0; j < M ->Nv; j++){ if(M ->G[Vertex][j] < INFITY && !Visited[j]){ Push_Heap(H, j, M ->G[Vertex][j], collected); } } } MinHeap Init_Heap(int N) { MinHeap H; H = (MinHeap)malloc(sizeof(struct Heap)); H ->Data = (DistNode*)malloc(sizeof(DistNode) * (N + 1)); H ->Data[0].Weight = MinValue; H ->Size = 0; return H; } void Push_Heap(MinHeap H, int index, int Weight, bool *collected) { int i; if(collected[index]){ for(i = 1; i <= H ->Size; i++){ if(index == H ->Data[i].V){ H ->Data[i].Weight = Weight; Counterpoise_Heap(H, index, i, Weight); return ; } } }else{ i = ++(H ->Size); Counterpoise_Heap(H, index, i, Weight); collected[index] = true; return ; } } void Counterpoise_Heap(MinHeap H, int index, int i, int Weight) { for(; Weight < H ->Data[i/2].Weight; i /= 2){ H ->Data[i].Weight = H ->Data[i/2].Weight; H ->Data[i].V = H ->Data[i/2].V; } H ->Data[i].Weight = Weight; H ->Data[i].V = index; return ; } bool IsEmpty_Heap(MinHeap H) { return (H ->Size == 0); } DistNode Pop_Heap(MinHeap H, bool *collected) { DistNode Min, Temp; int Parent, Child; if(IsEmpty_Heap(H)){ return H ->Data[0]; } Min = H ->Data[1]; Temp = H ->Data[H ->Size --]; collected[Min.V] = false; for(Parent = 1; Parent *2 < H ->Size; Parent = Child){ Child = Parent * 2; if(H ->Data[Child].Weight > H ->Data[Child + 1].Weight){ Child++; } if(Temp.Weight <= H ->Data[Child].Weight){ break; }else{ H ->Data[Parent].Weight = H ->Data[Child].Weight; H ->Data[Parent].V = H ->Data[Child].V; } } H ->Data[Parent].Weight = Temp.Weight; H ->Data[Parent].V = Temp.V; return Min; }