POJ 2421 Constructing Roads (Kruskal算法+压缩路径并查集 )

Constructing Roads

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 19884   Accepted: 8315

Description

There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected.

We know that there are already some roads between some villages and
your job is the build some roads such that all the villages are connect
and the length of all the roads built is minimum.

Input

The
first line is an integer N (3 <= N <= 100), which is the number
of villages. Then come N lines, the i-th of which contains N integers,
and the j-th of these N integers is the distance (the distance should be
an integer within [1, 1000]) between village i and village j.

Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then
come Q lines, each line contains two integers a and b (1 <= a < b
<= N), which means the road between village a and village b has been
built.

Output

You
should output a line contains an integer, which is the length of all the
roads to be built such that all the villages are connected, and this
value is minimum.

Sample Input

3
0 990 692
990 0 179
692 179 0
1
1 2

Sample Output

179 题目分析: 输入n个村庄,再输入一个邻接矩阵表示点到点的距离,再输入m条边,表示这m条边已经连接,不用考虑路径长度了,求如果想把所有的点都连接 还需要最短再修多长?算法分析:此题目和标准的模板有所差别,题目输入是一个二维邻接矩阵的值,然后在输入m条已经联通的边,也就是说这些边已经连接好了,这些边长就不要计算了。用Kruskal算法,并查集不仅要初始化,还要对这些边进行关联处理,建立父子关系。代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>

using namespace std;

struct node
{
    int u;
    int v;
    int w;
    bool operator <(const node&x)const  //node类自己的运算符重载,这样在sort时,直接写就可以了,不用调用函数了
    {
        return w<x.w;
    }
}q[5000];

int fa[105];
int findset(int x)
{
    return fa[x]!=x?fa[x]=findset(fa[x]):x;
} //带压缩路径的并查集

int main()
{
    int n, m;
    int u, v;
    int i, j;
    int dd;
    int e=0;
    scanf("%d", &n);
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=n; j++)
        {
            scanf("%d", &dd ); //因为是无向图,所以只需要存储一个上三角的数据或者下三角的数据就行,我存储的是上三角
            if(i<j)
            {
               q[e].u=i; q[e].v =j; q[e++].w=dd; //记录到结构体当中
            }
        }
    } //
    sort(q+0, q+e); //对结构体数组进行排序,边权小的靠前排序
    for(i=0; i<=n; i++)
    {
        fa[i]=i;  //并查集数组初始化,初始指向自己
    }
    scanf("%d", &m);  //读入m条边
    while(m--)
    {
        scanf("%d %d", &u, &v);
        fa[findset(u)] = findset(v); //表示u和v已经有路径相同不需要再修建道路,所以在并茶几上把他们并到一个子集里
    }
    int ans=0; //用来记录最后还需要修建的路径总长度
    for(int k=0; k<e; k++)
    {
        if(findset(q[k].u)!=findset(q[k].v) ) //如果这个结构体元素存储的两条村庄不属于同一个子集
        {
            fa[fa[q[k].u]] = fa[q[k].v]; //把这村庄合并到一个子集里 或者称合并到一棵树上
            ans+=q[k].w;
        }
    }
    printf("%d\n", ans );  //此代码还可以时间上优化一下,就是从输入m条边开始就统计已经加入生成树的边数,定义一个计数变量,当计数变量的值==n-1时就可以跳出上面的循环了    return 0;
}

这是从《数据结构 编程实验》那本书上看到的代码:用java写的,感觉并查集用的不错,但是在找边的时候的三层循环实在是不太好,时间性能太差,又很有没必要的循环

改写成结构体数组还是比较好使的。

代码如下:

import java.util.*;
import java.io.Reader;
import java.io.Writer;
import java.math.*; //导入java下的工具包

public class Main{
	public static void print(string x){  //输出最小生成树的边长和
		System.out.print(x);
	}
	static int[] fa; //并查集数组
	public static int findset(int x){
		return fa[x]!=x?fa[x]=findset(fa[x]):x;
	} //带压缩路径的并查集
	public static void main(string[] argv){ //定义main函数的参数是一个字符串类型的数组argv
		Scanner input = new Scanner(System.in); //定义java的标准输入
		while(input.hasNextInt() ){ //多组测试
			int N = input.nextInt();
			int [][]p = new int [N+1][N+1]; //为邻接矩阵申请内存
			for(int i=0; i<n; i++)
			{
				for(int j=0; j<n; j++)
				{
					p[i][j] = input.nextInt();
				}
			}
			fa = new int[N+1]; //为并查集数组申请内存
			for(int i=0; i<N; i++) fa[i]=i;  //父节点指针指向自己 初始化
			for(int m=intput.nextInt(); m>0; m-- )
			{
				fa[findset(input.nextInt()-1)] = findset(input.nextInt()-1); //建立父子关系
			}
			int ans=0; //新建公路的长度初始化
			for(int k=1; k<=1000; k++)
			{
				for(int i=0; i<N; i++)
				{
					for(int j=0; j<N; j++)
					{
						if(p[i][j]==k && findset(i)!=findset(j) )
						{
							fa[fa[i]] = fa[j];
							ans+=k;
						}
					}
				}
			}
			print(ans+"\n");
		}
	}
}
时间: 2024-10-27 08:06:56

POJ 2421 Constructing Roads (Kruskal算法+压缩路径并查集 )的相关文章

POJ 2421 Constructing Roads(Kruskal算法)

题意:给出n个村庄之间的距离,再给出已经连通起来了的村庄.求把所有的村庄都连通要修路的长度的最小值. 思路:Kruskal算法 课本代码: //Kruskal算法 #include<iostream> using namespace std; int fa[120]; int get_father(int x){ return fa[x]=fa[x]==x?x:get_father(fa[x]);//判断两个节点是否属于一颗子树(并查集) } int main(){ int n; int p[

poj 2421 Constructing Roads(kruskal)(基础)

Constructing Roads Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20643   Accepted: 8697 Description There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each

POJ 2421 Constructing Roads 修建道路 最小生成树 Kruskal算法

题目链接:POJ 2421 Constructing Roads 修建道路 Constructing Roads Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19698   Accepted: 8221 Description There are N villages, which are numbered from 1 to N, and you should build some roads such that e

HDU 1102 &amp;&amp; POJ 2421 Constructing Roads (经典MST~Prim)

链接:http://poj.org/problem?id=2421  或   http://acm.hdu.edu.cn/showproblem.php?pid=1102 Problem Description There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We

POJ 2421 Constructing Roads (最小生成树)

Constructing Roads Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2421 Appoint description:  System Crawler  (2015-05-27) Description There are N villages, which are numbered from 1 to N, and y

POJ 2421 Constructing Roads(最小生成树)

题意  在n个村庄之间修路使所有村庄连通  其中有些路已经修好了  求至少还需要修多长路 还是裸的最小生成树  修好的边权值为0就行咯 #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N = 105, M = 10050; int par[N], n, m, mat[N][N]; int ans; str

Kruskal算法(贪心+并查集=最小生成树)

http://www.51nod.com/ Kruskal算法的高效实现需要一种称作并查集的结构.我们在这里不介绍并查集,只介绍Kruskal算法的基本思想和证明,实现留在以后讨论. Kruskal算法的过程: (1) 将全部边按照权值由小到大排序. (2) 按顺序(边权由小到大的顺序)考虑每条边,只要这条边和我们已经选择的边不构成圈,就保留这条边,否则放弃这条边. 算法 成功选择(n-1)条边后,形成一个棵最小生成树,当然如果算法无法选择出(n-1)条边,则说明原图不连通. 以下图为例: 边排

POJ - 2421 Constructing Roads (最小生成树)

There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a

POJ 2421 Constructing Roads

题意:要在n个城市之间建造公路,使城市之间能互相联通,告诉每个城市之间建公路的费用,和已经建好的公路,求最小费用. 解法:最小生成树.先把已经建好的边加进去再跑kruskal或者prim什么的. 代码: #include<stdio.h> #include<iostream> #include<algorithm> #include<string> #include<string.h> #include<math.h> #includ