hduoj-1233 还是畅通工程(Prim + Kruskal)

本文深入探讨了信息技术领域的多个细分技术领域,包括前端开发、后端开发、移动开发、游戏开发、大数据开发等,并详细介绍了各自的关键技术和应用实例。

还是畅通工程

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 22226    Accepted Submission(s): 9939


Problem Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
 

Output
对每个测试用例,在1行里输出最小的公路总长度。
 

Sample Input
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
 

Sample Output
3 5
Hint
Hint
Huge input, scanf is recommended.
 

Prim(邻接矩阵,  134ms):
#include <stdio.h>
#include <string.h>
#define N 100

int n;
int map[N][N], low[N];
bool vis[N];

void Init(){
	memset(vis, 0, sizeof(vis));
	for(int i = 1; i <= n; i ++){
		low[i] = 0xfffffff;
		for(int j = 1; j <= n; j ++){
			map[i][j] = 0xfffffff;
		}
	}
}

int Prim(int choose){
	low[choose] = 0;
	vis[choose] = 1;
	for(int i = 1; i <= n; i ++){
		low[i] = map[choose][i];
	}
	
	int ans = 0;
	for(int j = 1; j < n; j ++){
		int Min = 0xfffffff;
		for(int i = 1; i <= n; i ++){
			if(!vis[i] && Min > low[i]){
				Min = low[i];
				choose = i;
			}
		}
		vis[choose] = 1;
		ans += Min;
		for(int i = 1; i <= n; i ++){
			if(!vis[i] && low[i] > map[choose][i]){
				low[i] = map[choose][i];
			}
		}
	}
	
	return ans;
}

int main()
{
	int start, end, len;
	while(scanf("%d", &n), n){
		Init();
		for(int i = 0; i < n * (n - 1) / 2; i ++){
			scanf("%d%d%d", &start, &end, &len);
			if(map[start][end] > len){
				map[start][end] = map[end][start] = len;
			}
		}
		
		int ans = Prim(1);
		
		printf("%d\n", ans);
	}
	
	return 0;
}


Prim(邻接表,  250ms):
#include <stdio.h>
#include <string.h>
#include <vector>
#define N 100

using namespace std;

struct Node{
	int next;
	int len;
};

int n;
int low[N];
bool vis[N];
vector<Node>q[N];

void Init(){
	memset(vis, 0, sizeof(vis));
	for(int i = 1; i <= n; i ++){
		low[i] = 0xfffffff;
		q[i].clear();
	}
}

int Prim(int choose){
	low[choose] = 0;
	vis[choose] = 1;
	for(int i = 0; i < q[choose].size(); i ++){
		int next = q[choose].at(i).next;
		int len = q[choose].at(i).len;
		low[next] = len;
	}
	
	int ans = 0;
	for(int j = 1; j < n; j ++){
		int Min = 0xfffffff;
		for(int i = 1; i <= n; i ++){
			if(!vis[i] && Min > low[i]){
				Min = low[i];
				choose = i;
			}
		}
		vis[choose] = 1;
		ans += Min;
		for(int i = 0; i < q[choose].size(); i ++){
			int next = q[choose].at(i).next;
			int len = q[choose].at(i).len;
			if(!vis[next] && low[next] > len){
				low[next] = len;
			}
		}
	}
	
	return ans;
}

int main()
{
	Node nw;
	int start, end, len;
	while(scanf("%d", &n), n){
		Init();
		for(int i = 0; i < n * (n - 1) / 2; i ++){
			scanf("%d%d%d", &start, &end, &len);
			nw.next = end;
			nw.len = len;
			q[start].push_back(nw);
			nw.next = start;
			q[end].push_back(nw);
		}
		
		int ans = Prim(1);
		
		printf("%d\n", ans);
	}
	
	return 0;
}


Kruskal(邻接表,  296ms):
#include <stdio.h>
#include <queue>
#define N 110

using namespace std;

struct Node{
	int start;
	int end;
	int len;
	friend bool operator < (const Node& a, const Node& b){
		return a.len > b.len;
	}
};

int n;
priority_queue<Node>q;
int Father[N];

void Init(){
	for(int i = 0; i <= n; i ++){
		Father[i] = i;
	}
}

int GetFather(int cur){
	return Father[cur] == cur ? cur : Father[cur] = GetFather(Father[cur]);
}

bool Join(int start, int end){
	int root1 = GetFather(start);
	int root2 = GetFather(end);
	
	if(root1 == root2){
		return 0;
	}
	else{
		Father[root1] = root2;
		return 1;
	}
}

int Kruskal(){
	int ans = 0;
	while(!q.empty()){
		Node cur = q.top();
		q.pop();
		
		if(Join(cur.start, cur.end)){
			ans += cur.len;
		}
	}
	
	return ans;
}

int main()
{
	Node nw;
	int start, end, len;
	while(scanf("%d", &n), n){
		Init();
		for(int i = 0; i < n * (n - 1) / 2; i ++){
			scanf("%d%d%d", &start, &end, &len);
			nw.start = start;
			nw.end = end;
			nw.len = len;
			q.push(nw);
		}
		
		int ans = Kruskal();
		
		printf("%d\n", ans);
	}
	
	return 0;
}


### Prim算法与Kruskal算法联合求解最小生成树的实现方法 Prim算法和Kruskal算法是两种经典的最小生成树(MST)求解方法。Prim算法适合稠密图,通过维护一个集合逐步扩展生成树;而Kruskal算法适合稀疏图,通过排序边并使用并查集避免环路来构造最小生成树。将这两种算法结合,可以通过以下方式实现: #### 算法思想 1. 使用Prim算法从某个顶点开始构建部分生成树,直到覆盖大部分顶点[^3]。 2. 在Prim算法完成后,利用剩余未处理的边进行Kruskal算法,确保所有顶点都被包含在最终的最小生成树中[^4]。 #### 实现步骤 以下是结合Prim算法和Kruskal算法的伪代码实现: ```python # Prim算法部分 def prim(graph, start_vertex): import heapq n = len(graph) visited = [False] * n min_heap = [(0, start_vertex)] # (weight, vertex) mst_edges = [] total_weight = 0 while min_heap: weight, u = heapq.heappop(min_heap) if visited[u]: continue visited[u] = True total_weight += weight for v, w in graph[u]: if not visited[v]: heapq.heappush(min_heap, (w, v)) mst_edges.append((u, v, w)) return mst_edges, total_weight, visited # Kruskal算法部分 def kruskal(graph, remaining_edges, visited): parent = list(range(len(graph))) rank = [0] * len(graph) def find_set(u): if parent[u] != u: parent[u] = find_set(parent[u]) return parent[u] def union_set(u, v): root_u = find_set(u) root_v = find_set(v) if root_u != root_v: if rank[root_u] > rank[root_v]: parent[root_v] = root_u elif rank[root_u] < rank[root_v]: parent[root_u] = root_v else: parent[root_v] = root_u rank[root_u] += 1 mst_edges = [] total_weight = 0 remaining_edges.sort(key=lambda x: x[2]) # Sort edges by weight for u, v, w in remaining_edges: if find_set(u) != find_set(v): union_set(u, v) mst_edges.append((u, v, w)) total_weight += w return mst_edges, total_weight # 联合算法 def combined_mst(graph, start_vertex): # Step 1: Use Prim to build a partial MST prim_edges, prim_weight, visited = prim(graph, start_vertex) # Step 2: Collect remaining edges for Kruskal remaining_edges = [] for u in range(len(graph)): for v, w in graph[u]: if not visited[u] or not visited[v]: remaining_edges.append((u, v, w)) # Step 3: Use Kruskal to complete the MST kruskal_edges, kruskal_weight = kruskal(graph, remaining_edges, visited) # Combine results total_mst_edges = prim_edges + kruskal_edges total_weight = prim_weight + kruskal_weight return total_mst_edges, total_weight ``` #### 结果解释 - `prim` 函数用于从指定起点开始构建部分最小生成树,并返回已访问的顶点集合。 - `kruskal` 函数接收剩余未处理的边,并通过并查集进一步扩展生成树。 - 最终结果为两部分生成树的合并,确保所有顶点都被包含在内[^1]。 #### 示例应用 假设输入图如下: ```python graph = [ [(1, 7), (2, 9), (5, 14)], [(0, 7), (2, 10), (3, 15)], [(0, 9), (1, 10), (3, 11), (5, 2)], [(1, 15), (2, 11), (4, 6)], [(3, 6), (5, 9)], [(0, 14), (2, 2), (4, 9)] ] start_vertex = 0 mst_edges, total_weight = combined_mst(graph, start_vertex) print("MST Edges:", mst_edges) print("Total Weight:", total_weight) ``` #### 注意事项 - Prim算法适用于稠密图,而Kruskal算法适用于稀疏图。因此,联合算法可以根据图的特性动态调整权重阈值[^2]。 - 在实际应用中,可能需要对输入图进行预处理以优化性能。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值