算法学习--Day8
今天重拾算法复习。
今天学习了两个类型的算法——并查集与最小生成树(MST)
简单记录一下并查集的大致内容。
一、并查集的内容大致作用为查找当前图中的点有几个集合。
该算法起到查询分组的情况。通过给定的条件使用数组记录该点对应的父节点,倘若两个点有相同的“祖先”,那他们肯定是属于同一个组的。
下面看几道例题:
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
输入描述:
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 注意:两个城市之间可以有多条道路相通,也就是说 3 3 1 2 1 2 2 1 这种输入也是合法的 当N为0时,输入结束,该用例不被处理。
输出描述:
对每个测试用例,在1行里输出最少还需要建设的道路数目。
示例1
这些题目属于查询结果的类型,相对基础一些。而下面我们介绍下使用克鲁斯卡尔来解最小生成树的问题:
这些题目的思想是在并查集的基础上进行延伸,一般来说是查询当前图中的最优解,此时我们也要使用组的概念,当两个节点属于同一个组的时候,那么这两个点就不可以连通。
例如:
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
输入描述:
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。 当N为0时,输入结束,该用例不被处理。
输出描述:
对每个测试用例,在1行里输出最小的公路总长度。
// // Created by 陈平 on 2018/6/5. // #include "iostream" #include "stdio.h" #include "algorithm" using namespace std; int tree[101]; struct Edge{ int a; int b; int value; }edges[6000]; int findRoot(int a){ if(tree[a]==-1) return a; else{ int tmp = findRoot(tree[a]); tree[a] = tmp; return tmp; } } bool cmp(Edge a,Edge b){ return a.value<b.value; } int main(){ int n; while (scanf("%d",&n)!=EOF&&n!=0){ for (int i = 1; i <=n*(n-1)/2 ; ++i) { cin>>edges[i].a>>edges[i].b>>edges[i].value; } sort(edges+1,edges+n*(n-1)/2+1,cmp); for (int j = 1; j <=n ; ++j) { tree[j]=-1; } int ans=0; for (int k = 1; k < n*(n-1)/2; ++k) { int a,b; a = findRoot(edges[k].a); b = findRoot(edges[k].b); if(a!=b){ tree[a]=b; ans+=edges[k].value; } } cout<<ans<<endl; } }
面对最小生成树的问题,我们的思路是将输入的路径进行从小到大的排序,并以此取合适的路径。
题目描述
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
输入描述:
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。 当N为0时输入结束。
输出描述:
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
// // Created by 陈平 on 2018/6/6. // #include "stdio.h" #include "iostream" #include "algorithm" using namespace std; int tree[101]; struct Edge{ int a; int b; int cost; int flag; }edges[6000]; int findRoot( int a){ if(tree[a]==-1) return a; else{ int tmp = findRoot(tree[a]); tree[a] = tmp; return tmp; } } bool cmp(Edge a,Edge b){ return a.cost<b.cost; } int main(){ int n; while (scanf("%d",&n)!=EOF && n!=0){ for (int i = 1; i <=n ; ++i) { tree[i]=-1; } int ans=0; for (int j = 1; j <=n*(n-1)/2 ; ++j) { cin>>edges[j].a>>edges[j].b>>edges[j].cost>>edges[j].flag; if(edges[j].flag==1){ //重点部分 int a,b; a = findRoot(edges[j].a); b = findRoot(edges[j].b); if(a!=b) tree[a] = b; } } sort(edges+1,edges+1+n*(n-1)/2,cmp); for (int k = 1; k <=n*(n-1)/2 ; ++k) { int a,b; a = findRoot(edges[k].a); b = findRoot(edges[k].b); if(a!=b){ tree[a] = b; ans+=edges[k].cost; } } cout<<ans<<endl; } }
因为菜,所以仍在努力。