HDU 1863
来源:互联网 发布:yap—yum示意图 编辑:程序博客网 时间:2024/05/16 12:13
这是一道最小生成树的题目,很适合刚学完Prim算法或Kruskal算法的人来练手。
Prim算法:首先,把图中的顶点集分成Va和Vb两个集合,Va中的点属于最小生成树,Vb中的点属于待选的点。起初,Va中只有一个点,这个点是任意选择的。两个集合间存在相互连接的边,选择其中权值最小的边,并把对应的点加入集合Va中,重复上述选择过程,直到无边可选。如果Vb中没有点,则说明图G存在最小生成树,否则图G不存在最小生成树。
Kruskal算法:每次选择图中权值最小,但又不会与已选择的边构成环的边,直到无边可选,如果选择的边数为n-1(假设图的顶点数为n),那么图G存在最小生成树,否则图G不存在最小生成树。
再说详细点,在用Prim算法时,我用了链式前向星来保存图,判断两个集合间的权值最小的边时,我用了优先队列,这样比单纯用二维数组更快(不过我没正的对比过)。在用Kruskal算法时,我用了前向星来存图,用并查集来判断所选的边是否与已存在的边构成环。(关于链式前向星和前向星的讲解可以参考《ACM—ICPC程序设计系列 图论及应用》(哈尔滨工业大学出版社)第一章)
代码(G++):
Prim算法:
#include <cstdlib>#include <iostream>#include <queue>#define MAXp 105#define MAXe 9900using namespace std;int vis[MAXp],head[MAXp],m; //true表示属于生成树的点集,false表示不属于 struct edge{ int to; int next; int w; };edge array[MAXe*2];struct cmp{ bool operator() (int a,int b) { return array[a].w>array[b].w; }};priority_queue<int,vector<int>,cmp> pq;void prim(int u,int &ans,int &amount){ if(amount==m) return; int i,tmp,v; for(i=head[u];i!=-1;i=array[i].next) pq.push(i); while(!pq.empty()) { tmp=pq.top(); pq.pop(); v=array[tmp].to; if(!vis[v]) { ans+=array[tmp].w; vis[v]=true; amount++; prim(v,ans,amount); break; } } }int main(int argc, char *argv[]){ int n,i,u,v,w,c,ans,amount; while(scanf("%d %d",&n,&m)&&n!=0) { memset(vis,false,sizeof(vis)); memset(head,-1,sizeof(head)); c=ans=0; for(i=0;i<n;i++) { scanf("%d %d %d",&u,&v,&w); array[c].to=v; array[c].w=w; array[c].next=head[u]; head[u]=c; c++; array[c].to=u; array[c].w=w; array[c].next=head[v]; head[v]=c; c++; } vis[1]=true; amount=1; prim(1,ans,amount); while(!pq.empty()) pq.pop(); if(amount<m) printf("?\n"); else printf("%d\n",ans); } system("PAUSE"); return EXIT_SUCCESS;}
Kruskal算法:
#include <cstdlib>#include <iostream>#include <algorithm>#define MAXe 9900#define MAXp 100using namespace std;struct edge{ int u; int v; int w; };edge array[MAXe];int fa[MAXp];bool cmp(edge a,edge b){ if(a.w!=b.w) return a.w<b.w; if(a.u!=b.u) return a.u<b.u; return a.v<b.v; }int find(int a){ if(fa[a]!=a) fa[a]=find(fa[a]); return fa[a];}int main(int argc, char *argv[]){ int n,m,i,u,v,w,c,ans,amount,p,fu,fv; while(scanf("%d %d",&n,&m)&&n!=0) { c=0; for(i=0;i<n;i++) { scanf("%d %d %d",&u,&v,&w); array[c].u=u; array[c].v=v; array[c].w=w; c++; } sort(array,array+c,cmp); for(i=1;i<=m;i++) fa[i]=i; ans=amount=p=0; for(i=1;i<m;i++) { while(p<c) { fu=find(array[p].u); fv=find(array[p].v); if(fu!=fv) { fa[fu]=fv; ans+=array[p].w; amount++; break; } p++; } } if(amount==m-1) printf("%d\n",ans); else printf("?\n"); } system("PAUSE"); return EXIT_SUCCESS;}
题目(http://acm.hdu.edu.cn/showproblem.php?pid=1863):
畅通工程
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Problem Description
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
Output
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input
3 31 2 11 3 22 3 41 32 3 20 100
Sample Output
3?
0 0
- hdu 1863 hdu 1879 hdu 1875
- HDU 1863
- HDU 1863
- hdu 1863
- hdu 1863
- hdu 1863
- HDU 1863
- hdu 1863
- hdu 1863
- HDU 1863
- HDU 1863
- hdu-1863
- hdu 1863
- HDU-1863
- hdu 1863 hdoj 1863
- HDU 1863 畅通工程
- hdu 1863 畅通工程
- hdu 1863 畅通工程
- Spring与Hibernate两种组合方式
- 第五周(项目一拓展)——矩形类的构造函数。
- MFC中使用ADO 插入Oracle,数据类型
- 借贷记联机脚本
- C语言之 短路原则
- HDU 1863
- Python yield 使用浅析
- 给中国学生的第二封信:从优秀到卓越
- Ubuntu 10下裸装JDK 1.6
- UE4中的AI解析1
- Oracle Data Guard_ 备库以只读或读写方式打开访问
- 【CareerCup】Stacks and Queues—Q3.3
- 关于静态成员变量与方法的一个实例
- 一步步学习微软InfoPath2010和SP2010--第三章节--表单设计基础:处理InfoPath布局、控件和视图(9)--添加第二个视图到Flight Delay表单