问题描述
雷雷承包了很多片麦田,为了灌溉这些麦田,雷雷在第一个麦田挖了一口很深的水井,所有的麦田都从这口井来引水灌溉。
为了灌溉,雷雷需要建立一些水渠,以连接水井和麦田,雷雷也可以利用部分麦田作为“中转站”,利用水渠连接不同的麦田,这样只要一片麦田能被灌溉,则与其连接的麦田也能被灌溉。
现在雷雷知道哪些麦田之间可以建设水渠和建设每个水渠所需要的费用(注意不是所有麦田之间都可以建立水渠)。请问灌溉所有麦田最少需要多少费用来修建水渠。
为了灌溉,雷雷需要建立一些水渠,以连接水井和麦田,雷雷也可以利用部分麦田作为“中转站”,利用水渠连接不同的麦田,这样只要一片麦田能被灌溉,则与其连接的麦田也能被灌溉。
现在雷雷知道哪些麦田之间可以建设水渠和建设每个水渠所需要的费用(注意不是所有麦田之间都可以建立水渠)。请问灌溉所有麦田最少需要多少费用来修建水渠。
输入格式
输入的第一行包含两个正整数n, m,分别表示麦田的片数和雷雷可以建立的水渠的数量。麦田使用1, 2, 3, ……依次标号。
接下来m行,每行包含三个整数a i, b i, c i,表示第a i片麦田与第b i片麦田之间可以建立一条水渠,所需要的费用为c i。
接下来m行,每行包含三个整数a i, b i, c i,表示第a i片麦田与第b i片麦田之间可以建立一条水渠,所需要的费用为c i。
输出格式
输出一行,包含一个整数,表示灌溉所有麦田所需要的最小费用。
样例输入
4 4
1 2 1
2 3 4
2 4 2
3 4 3
1 2 1
2 3 4
2 4 2
3 4 3
样例输出
6
样例说明
建立以下三条水渠:麦田1与麦田2、麦田2与麦田4、麦田4与麦田3。
评测用例规模与约定
前20%的评测用例满足:n≤5。
前40%的评测用例满足:n≤20。
前60%的评测用例满足:n≤100。
前40%的评测用例满足:n≤20。
前60%的评测用例满足:n≤100。
所有评测用例都满足:1≤n≤1000,1≤m≤100,000,1≤ci≤10,000。
这道题目就是求最小生成树。楼主用了两种方法实现 一种是kruskal
还有一个借鉴了算法导论上的并查集 但是美中不足的是代码运行超时 只得了90分 可能是排序算法的问题
package com.graph;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class SmallTreeNew {
//最小生成树
private static int f[] = new int[1005];
public static class Edges implements Comparable<Edges>
{
public int a,b,c;
public int compareTo(Edges arg0) {
return this.c-arg0.c;
}
}
static int find(int a)
{
if(f[a]!=a)
{
f[a]=find(f[a]);
}
return f[a];
}
public static void main(String[] args) {
Queue<Edges> queue = new PriorityQueue<Edges>(1000);
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
for(int i = 0;i<=n;i++)
{
f[i] = i;
}
Edges edge = null;
for(int i = 1;i<m+1;i++)
{
edge = new Edges();
edge.a = in.nextInt();
edge.b = in.nextInt();
edge.c = in.nextInt();
queue.add(edge);
}
in.close();
int sum= 0;
int i =1;
n--;
while(n>0 && i<=m)
{
Edges abc = queue.poll();
int a = find(abc.a);
int b = find(abc.b);
if(a!=b)
{
f[a] = b;
sum+=abc.c;
n--;
}
i++;
}
System.out.print(sum);
}
}
接着还用一种方法 用了并查集
package com.graph;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
public class SmallTree {
int n;
static int father[] = new int[1005];
static int rnk[] = new int[1005];
public static class Edges implements Comparable<Edges>
{
public int a,b,c;
public int compareTo(Edges arg0) {
return this.c-arg0.c;
}
}
static int findSet(int x) //非递归路径压缩查找
{
int root = x; //根节点
while (root != father[root])
root = father[root];
int tem = x;
while (tem != root) //路径压缩
{
int temFather = father[tem];//暂存父亲节点
father[tem] = root; //更新父亲为根
tem = temFather; //移动到父亲节点
}
return root; //返回根节点
}
static int unionSet(int x, int y) //合并
{
int s = 0;
x = findSet(x);
y = findSet(y);
if (x == y)
return 0;
if (rnk[x] > rnk[y])
father[y] = x;
else
{
father[x] = y;
if(rnk[x] == rnk[y])
s =1;
rnk[y] +=s;
}
return 1;
}
public static void main(String[] args) {
Queue<Edges> queue = new PriorityQueue<Edges>();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
for(int i = 0;i<=n;i++)
{
father[i] = i;
}
for(int i = 1;i<m+1;i++)
{
Edges edge = new Edges();
edge.a = in.nextInt();
edge.b = in.nextInt();
edge.c = in.nextInt();
queue.add(edge);
}
in.close();
int sum= 0;
for (int i = 0; i < m; i++) //遍历边
{
Edges abc = queue.poll();
if (unionSet(abc.a, abc.b) == 1) //合并边的两个节点所在集合
sum += abc.c; //如果节点集合不同,加入最小生成树中
}
System.out.println(sum);
}
}