08-图7 公路村村通

很明显聪明的同学已经发现,这是一个稠密图,所以用邻接矩阵。可以很好的表达,比邻接表有优势,所以,采用邻接矩阵破题,

很明显,这是一个最小生成树问题,也可以认为贪心算法,接下来我将分别展示两个实现路径,第一个 prim 算法, 第二个kruskal算法(等等)。

 第一个 prim 算法,真是,咋又出问题了,鲁棒性也太差了。

测试点提示内存(KB)用时(ms)结果得分
0sample换数字,各种回路判断3641

答案正确

15 / 15
1M<N-1,不可能有生成树1761

答案正确

2 / 2
2M达到N-1,但是图不连通3441

答案正确

2 / 2
3最大N和M,连通42727

答案错误

0 / 5
4最大N和M,不连通40885

答案正确

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

  • 12
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值