还是畅通工程

                                                                           Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

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.

在无向带权连通图G中,如果一个连通子树包含所有顶点,并且连接这些顶点的边权之和最小,

那么这个连通子图就是G的最小生成树。求最小生成树的一个常见算法是Prim算法。

prim算法(时间复杂度为O(n^3)):

Prim算法的基本思想是:

1)设置两个集合V和S,任意选择一个顶点作为起始顶点,将起始顶点放入集合S,其余顶点存入集合

V中;2)然后使用贪心策略,选择一条长度最短并且端点分别在S和V中边(即为最小生成树的中的一条

边),将这条边在V中的端点加入到集合S中;3)循环执行第2)步直到S中包含了所有顶点。

#include<stdio.h>
#include<string.h>
#define inf 0x3f3f3f3f
int map[100][100],s[100],vis[100];
int n,m;
int prim()
{int i,j,t,p,min,minpos,cnt;int ans=0;cnt=0;  /*记录已经加入的点的个数*/vis[1]=1; /*从第一个点开始找*/s[cnt++]=1; /*s数组保存已经加入的点*/while(cnt<n)  /*点还没有加入完*/{t=cnt;min=inf;for(i=0;i<t;i++) {p=s[i];for(j=1;j<=n;j++){if(!vis[j]&&map[p][j]<min)  /*在已经加入的点和没加入的点之间找出一条最短路,*/{min=map[p][j];minpos=j; /*记录下新找到的最短路的端点*/}}}ans+=min;  s[cnt++]=minpos; /*更新已经加入的点*/vis[minpos]=1;  }return ans;
}
int main()
{int u,v,w,i;while(~scanf("%d",&n)&&n){m=n*(n-1)/2;memset(vis,0,sizeof(vis));memset(map,inf,sizeof(map));for(i=0;i<m;i++){scanf("%d%d%d",&u,&v,&w);map[u][v]=w;map[v][u]=w;}int sum=prim();printf("%d\n",sum);}return 0;
}

上面的算法有三个循环,时间复杂度为O(N^3),考虑到由于使用的是贪心策略,则每添加一个新顶点到集合S中的时候,才会改变V中每个点到S中的点的最小边的长度。因此可以用一个数组nearest[N](N为顶点个数)记录在生成最小数的过程中,记录V中每个点的到S中点的最小边长,用另外一个数组adj[N]记录使得该边最小的对应的邻接点。那么O(N)的时间了找到最短的边,并且能在O(N)的时间里更新nearest[N]和adj[N]。因此可以得到O(N^2)的算法。

#include<stdio.h>
#include<string.h>
#define inf 0x3f3f3f3f
int map[100][100];
int n,m;
/*记当前生成树的节点集合为S,未使用的节点结合为V*/
int vis[100]; //标记某个点是否在S中
int adj[100]; //记录与S中的点最接近的点
int nearest[100];  //记录V中每个点到S中的点的最短边
int prim()
{int i,j,min;int ans=0;vis[1]=1;for(i=2;i<=n;i++){nearest[i]=map[1][i]; adj[i]=1;}int cnt=n-1; /*记录边的条数*/while(cnt--){min=inf;j=1;for(i=1;i<=n;i++){if(!vis[i]&&nearest[i]<min){min=nearest[i];j=i;}}ans+=map[j][adj[j]];vis[j]=1;for(i=1;i<=n;i++){if(!vis[i]&&map[i][j]<nearest[i]){nearest[i]=map[i][j]; /*找最短的边*/adj[i]=j; /*找最接近的点*/}}}return ans;
}
int main()
{int i,sum,u,v,w;while(~scanf("%d",&n)&&n){memset(vis,0,sizeof(vis));memset(map,0,sizeof(map));m=n*(n-1)/2;for(i=0;i<m;i++){scanf("%d%d%d",&u,&v,&w);map[u][v]=map[v][u]=w;}sum=prim();printf("%d\n",sum);}return 0 ;
}
Kruskal算法(时间复杂度O(ElogE),E为边数):

给定无向连同带权图G = (V,E),V = {1,2,...,n}。Kruskal算法构造G的最小生成树的基本思想是:

(1)首先将G的n个顶点看成n个孤立的连通分支。将所有的边按权从小大排序。

(2)从第一条边开始,依边权递增的顺序检查每一条边。并按照下述方法连接两个不同的连通分支:当查看到第k条边(v,w)时,如果端点v和w分别是当前两个不同的连通分支T1和T2的端点是,就用边(v,w)将T1和T2连接成一个连通分支,然后继续查看第k+1条边;如果端点v和w在当前的同一个连通分支中,就直接再查看k+1条边。这个过程一个进行到只剩下一个连通分支时为止。

此时,已构成G的一棵最小生成树。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int father[100];
int n,m;
struct point
{int u;int v;int w;
}a[5000];
bool comp(point a1,point a2) /*按权值从小到大排序*/
{return a1.w<a2.w;
}
void initial() /*并查集初始化*/
{for(int i=0;i<=100;i++)father[i]=i;
}
int find(int x)  /*查找根节点*/
{if(father[x]==x)return x;return find(father[x]);
}
void merge(int p,int q)  /*合并两个集合*/
{int pp=find(p);int qq=find(q);if(pp!=qq){if(pp<qq)father[qq]=pp;elsefather[pp]=qq;}
}
int kruskal()
{initial();  /*初始化*/int ans=0;sort(a+1,a+m+1,comp); /*排序*/for(int i=1;i<=m;i++){int x=find(a[i].u);int y=find(a[i].v);if(x!=y)  /*两端点不属于同一集合*/{ans+=a[i].w;merge(x,y); /*合并*/}}return ans;
}
int main()
{int i,sum;while(~scanf("%d",&n)&&n!=0){m=n*(n-1)/2;for(i=1;i<=m;i++)scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);sum=kruskal();printf("%d\n",sum);}return 0;
}

hdu 1233 还是畅通工程 最小生成树(prim算法 + kruskal算法)相关推荐

  1. hdu 1233 还是畅通工程(最小生成树的Prim和Kruskal两种算法的c++实现)(prim算法详解)...

    赤裸裸滴最小生成树(MST),刚学的玩意,用两种方法熟练一下.(都是greedy) Kruskal方法:先对边按照代价非递减排序,再不断添加边且不产生环路,当边数=点数-1结束.判断加入(v,w)是否 ...

  2. 还是畅通工程(prim和kruskal)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1233 还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    ...

  3. 最小生成树(Prim、Kruskal)算法,秒懂!

    前言 在数据结构与算法的图论中,(生成)最小生成树算法是一种常用并且和生活贴切比较近的一种算法.但是可能很多人对概念不是很清楚,什么是最小生成树? 一个有 n 个结点的连通图的生成树是原图的极小连通子 ...

  4. HDU 1233 还是畅通工程(最小生成树 Prim+Kruskal)

    原题地址 http://acm.hdu.edu.cn/showproblem.php?pid=1233 题意:(最小生成树裸题)有N个村庄,给出村庄两两之间的距离,要求铺设公路,使得任何两个村庄间都可 ...

  5. HDU 1863畅通工程(最小生成树)(prim算法)

    畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  6. HDU 1233 还是畅通工程(最小生成树)

    传送门 还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  7. hdu 1879 继续畅通工程 最小生成树

    继续畅通工程                                                                             Time Limit: 2000/ ...

  8. HDU 1879 继续畅通工程 最小生成树

    继续畅通工程 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description ...

  9. 畅通工程//最小生成树prim

    题目: 畅通工程 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

最新文章

  1. 使用python爬取视频
  2. (原)ubuntu中使用conda安装tensorflow-gpu
  3. python的id方法_python中id()函数的实用研究实例
  4. java 9999 符号_java 9999(示例代码)
  5. html调出手机系统设置,手机怎么打开路由器设置界面?
  6. S3C2440扩展SDRAM
  7. 怎样把文件传到华为云服务器,如何把文件传到云服务器上
  8. C# 实现将文本txt生成图片
  9. The parent project must have a packaging type of POM
  10. linux查看ip访问日志文件,linux分析apache日志获取最多访问的前10个IP
  11. 模式匹配和正则表达式_python
  12. 不能错过!CIO不可不知的“数据经济学” | 凌云时刻
  13. EBT 道客巴巴的加密与破解 - 实用组合工具箱
  14. Android自动升级框架
  15. 如何利用信息差来创造价值?
  16. 国庆假期,人在囧途,感慨颇多
  17. 大屏可视化解决方案:公安大数据平台建设
  18. Littlefs移植,FLASH用的是W25Q32
  19. html语言加号点一下变成减号6,CSS3 linear-gradient线性渐变生成加号和减号的方法...
  20. 如何安装使用Oracle10g

热门文章

  1. 诊断案例:从实例挂起到归档失败和内存管理的蝴蝶效应
  2. 英特尔在中国投资55亿美元非易失性存储项目投产
  3. C# 学习笔记1 .NET平台,C#的重要概念
  4. sainsbury online order
  5. TCP粘包产生的原因
  6. 最近使用的两个工具 winscp和xshell
  7. 【转】内存耗用:VSS/RSS/PSS/USS
  8. C# lambda表达式及初始化器
  9. vc2010多线程使用std标准模板库容器DEBUG版迭代器BUG
  10. 微信小程序样式入门到精通(wxss)课程007-文本-text-align水平对齐