hdu 3371 Java 最小生成树+并查集

原题链接

考虑到原来已经有一定的城市已经相连,这里要计算出总共的根节点数目rootNum,方法为寻找每一个节点的父节点,若该节点的父节点与自身相等,则rootNum++;最终只需从可选边中用克鲁斯卡尔算法选择出rootNum-1条边即满足要求。

由于Scanner过于慢,这里读入数据用到了其他人写的内部快速输入类。
ACM—JAVA最快的输入方式

下面附上ac代码
在这里插入图片描述

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;


public class Main
{
	static class Reader
	{
		BufferedReader br;
		StringTokenizer st;
		Reader(InputStream input)
		{
			br = new BufferedReader(new InputStreamReader(input));
			st = null;
		}
		public String next() throws IOException
		{
			while(st==null || !st.hasMoreTokens())
			{
				String str = br.readLine();
				if(str==null)
					return null;
				st = new StringTokenizer(str);
			}
			return st.nextToken();
		}
		public int nextInt() throws NumberFormatException, IOException
		{
			return Integer.parseInt(next());
		}
	}
	static class Edge
	{
		public int start,end,value;
		public String toString()
		{
			return start+" "+end+" "+value;
		}
	}
	
	static int T,N,M,K;
	static int[] pre;
	static Edge[] edge;
	static int rootNum;
	static int find(int n)
	{
		if(n==pre[n])
			return n;
		else
			return pre[n] = find(pre[n]);
	}
	static void initData(Reader in) throws NumberFormatException, IOException
	{
		N = in.nextInt();
		M = in.nextInt();
		K = in.nextInt();
		pre = new int[N+1];
		edge = new Edge[M+1];
		rootNum = 0;
		for(int i=1;i<=N;i++)
			pre[i] = i;
		for(int i=1;i<=M;i++)
		{
			edge[i] = new Edge();
			edge[i].start = in.nextInt();
			edge[i].end = in.nextInt();
			edge[i].value = in.nextInt();
		}
		while(K-->0)
		{
			int t = in.nextInt();
			int root = find(in.nextInt());
			for(int i=1;i<t;i++)
			{
				int root1 = find(in.nextInt());
				if(root!=root1)
					pre[root1]=root;
			}
		}
		for(int i=1;i<=N;i++)
			if(pre[i]==i)
				rootNum++;
	}
	static void swap(int a,int b)
	{
		Edge t = edge[a];
		edge[a] = edge[b];
		edge[b] = t;
	}
	static int elemSwap(int left,int right)
	{
		int point = edge[left].value;
		int i = left;
		int j = right;
		while(i<j)
		{
			while(i<j && edge[j].value>=point)
				j--;
			while(i<j && edge[i].value<=point)
				i++;
			swap(i,j);
		}
		swap(left,j);
		return j;
	}
	static void quickSort(int left,int right)
	{
		if(left>=right)
			return;
		if(left<1 || right>M)
			return;
		int mid = elemSwap(left,right);
		quickSort(left,mid-1);
		quickSort(mid+1,right);
	}
	static void showData()
	{
		quickSort(1,M);
		for(int i=1;i<=M;i++)
			System.out.println(edge[i]);
		for(int i=1;i<=N;i++)
			System.out.printf("%3d",pre[i]);
		System.out.println();
		System.out.println("rootNum="+rootNum);
	}
	static int Kruskal()
	{
		int sum = 0;
		int cnt = 0;
		quickSort(1,M);
		for(int i=1;i<=M;i++)
		{
			if(cnt==rootNum-1)
				break;
			int roota = find(edge[i].start);
			int rootb = find(edge[i].end);
			if(roota!=rootb)
			{
				cnt++;
				sum += edge[i].value;
				pre[roota] = rootb;
			}
		}
		if(cnt==rootNum-1)
			return sum;
		else
			return -1;
	}
	public static void main(String[] args) throws NumberFormatException, IOException
	{
		Reader in = new Reader(System.in);
		T = in.nextInt();
		while(T-->0)
		{
			initData(in);
//			showData();
			System.out.println(Kruskal());
		}
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值