博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[置顶] NYOJ38 布线问题
阅读量:6541 次
发布时间:2019-06-24

本文共 3270 字,大约阅读时间需要 10 分钟。

题目链接:

题目分析:

其实就是求图的最小生成树。有两种方法。prim法和kruskal法。prim法只与节点有关,与边无关,所以适合于求边稠密的网的最小生成树。而kruskal算法与边有关,故其适合于求边比较稀疏的网络。
prim算法:
1)初始化set集为随意的一个节点,这里初始化为1。
2)找出与set集中的点相连的,花费最小的并且不再set集中的点,加入set集中。为了计算的方便,先将每个节点相连的所有边按权值升序排列。
3)直到所有的点都加到set集中,算法就停止了。
kruskal算法:
1)每次找权值最小的边,如果节点没有访问过,就加到set集中。如果访问过了,就合并两个set集。
2)这里为了剪去不必要的迭代,如果连通区域为1,并且所有的点都已经访问过了,就退出。

参考代码:

prim算法的代码:

#include
#include
#include
struct NODE{ int to; int w;};NODE Map[501][501];//Map[i][0].to存放节点i相邻的点的个数bool used[501];int set[501];int compare(const void *a, const void *b){ NODE *p1 = (NODE *)a; NODE *p2 = (NODE *)b; return p1->w - p2->w;}void GetMap(int n){ for(int i = 1; i <= n; ++i) qsort(&Map[i][1], Map[i][0].to, sizeof(Map[i][0]), compare);}int Prim(int n){ int num = 1;//set集合内点的个数 int i,j; int ans = 0; NODE temp; set[0] = 1; used[1] = true; while(num < n) { temp.to = -1; temp.w = 101; for(i = 0; i < num; ++i) { for(j = 1; j <= Map[set[i]][0].to; ++j) { if(!used[Map[set[i]][j].to]) { if(Map[set[i]][j].w < temp.w) temp = Map[set[i]][j]; break; } }//end for j }//end for i if(temp.to != -1) { ans += temp.w; set[num++] = temp.to; used[temp.to] = true; } }//end for while return ans;}int main(){ int t,i; int v,e; int a,b,c; int ans; scanf("%d", &t); while(t--) { memset(used,0,sizeof(used)); scanf("%d %d", &v, &e); for(i = 0; i <= v; ++i) Map[i][0].to = 0; for(i = 0; i < e; ++i) { scanf("%d %d %d", &a, &b, &c); ++(Map[a][0].to); ++(Map[b][0].to); Map[a][Map[a][0].to].to = b; Map[a][Map[a][0].to].w = c; Map[b][Map[b][0].to].to = a; Map[b][Map[b][0].to].w = c; } scanf("%d", &b); for(i = 1; i < v; ++i) { scanf("%d", &a); b = b < a ? b : a; } GetMap(v); ans = Prim(v); ans += b; printf("%d\n", ans); } return 0;}

kruskal算法的代码:

#include
#include
#include
struct EDGE{ int from; int to; int w;};EDGE edge[124760];//所有的边bool used[501];int set[501];int compare(const void *a, const void *b){ EDGE *p1 = (EDGE *)a; EDGE *p2 = (EDGE *)b; return p1->w - p2->w;}int find(int k){ int r = set[k]; while(r != set[r]) r = set[r]; return r;}void Merge(int r1, int r2){ if(r1 < r2) set[r2] = r1; else set[r1] = r2;}int Kruskal(int v, int e){ int ans = 0; int t, num;//t为连通区域的个数,num为已访问的节点的个数 int r1, r2; t = num = 0; while(num != v && t != 1) { for(int i = 0; i < e; ++i) { if(!used[edge[i].from]) { ++t; ++num; used[edge[i].from] = true; } if(!used[edge[i].to]) { ++t; ++num; used[edge[i].to] = true; } r1 = find(edge[i].from); r2 = find(edge[i].to); if(r1 != r2) { --t; Merge(r1, r2); ans += edge[i].w; } }//end for i }//end while return ans;}int main(){ int t,i; int v,e; int a,b,c; int ans; scanf("%d", &t); while(t--) { memset(used,0,sizeof(used)); scanf("%d %d", &v, &e); for(i = 1; i <= v; ++i) set[i] = i; for(i = 0; i < e; ++i) { scanf("%d %d %d", &a, &b, &c); edge[i].from = a; edge[i].to = b; edge[i].w = c; } qsort(edge, e, sizeof(edge[0]), compare); scanf("%d", &b); for(i = 1; i < v; ++i) { scanf("%d", &a); b = b < a ? b : a; } ans = Kruskal(v, e); ans += b; printf("%d\n", ans); } return 0;}

由于prim方法针对节点,而kruskal方法针对边,所以二者的数据结构有点不一样。

转载地址:http://sfsdo.baihongyu.com/

你可能感兴趣的文章
用户ID的代码生成
查看>>
win7经常出现“关闭xxxx前您必须关闭所有会话框”
查看>>
SNMP安全配置的两种方法(也可同一时候兼顾配置两种方法)
查看>>
MongoDB 自己定义函数
查看>>
Summary Day30
查看>>
逆向输出回环数组
查看>>
自己动手,实现“你的名字”滤镜
查看>>
高清摄像头MIPI CSI2接口浅解【转】
查看>>
C# CancellationTokenSource和CancellationToken的实现
查看>>
PCIE BAR空间
查看>>
如何用数学课件制作工具画角平分线
查看>>
VS2015 中统计整个项目的代码行数
查看>>
UWP控件与DataBind
查看>>
bash: php: command not found
查看>>
XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix
查看>>
数据恢复软件如何换机使用?
查看>>
《高性能mysql》到手
查看>>
(转)关于如何学好游戏3D引擎编程的一些经验
查看>>
使用Kotlin为你的APP自定义一个统一的标题栏
查看>>
EF各版本增删查改及执行Sql语句
查看>>