国王的烦恼+蓝桥算法真题+并查集+java实现之史上最详细图文分析

本文介绍了如何利用并查集解决蓝桥杯竞赛中的一道题目,通过逆向思维分析问题,将集合减少转化为满意度增加。程序实现了并查集的初始化、查询和合并操作,并用ArrayList存储和排序桥梁信息。通过对桥梁按天数降序排列,计算出不满的天数,从而得出答案。
摘要由CSDN通过智能技术生成

蓝桥杯 试题 历届试题 国王的烦恼 并查集

蓝桥杯 试题 历届试题 国王的烦恼 并查集 - 走看看

1、解这样的题,也可以有其他的方法,最好的方法就是采用并查集来解。

关于并查集的基本算法的讲解和代码,我们PPT中有。

2、分析题意画示意图:

(1)输入:

(2)小岛与桥示意图:

 

 

 

但是并查集没有办法表示集合的增加,只能表示集合的减少。

所以我们逆向思维,

从第四天到第三天,集合减少,人民满意度增加(可以过桥)。反过来就等于,从第三天到第四天,集合增加,人民抱怨。

从第三天到第二天,集合减少,人民满意度增加(可以过桥)。反过来就等于,从第2天到第3天,集合增加,人民抱怨。

从第二天到第一天,集合数保持不变。所以满意度和抱怨度都不变。

在这样的分析基础上,再结合并查集的代码,一起来解决这个集合类的问题。

3. 算法实现如下:

package qs;

/*
 * 
 * 测试数据为:
4 4
1 2 2
1 3 2
2 3 1
3 4 3
 * 
 * 
 * 
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

public class testunionfind {
   
	static int s[];
   
  // static Bridge[] b=new Bridge[1000000+1];  这个数组排序无力,去掉,数据结构选择有问题
  static ArrayList<Bridge> blist=new ArrayList<Bridge>();
   
	public static void main(String[] args) {
		// TODO Auto-generated method stub
       Scanner sc=new Scanner(System.in);
       int n=sc.nextInt();//小岛的个数
       int m=sc.nextInt(); //桥的数目
       s=new int[n+1];//下标0没有使用
       for(int i=1;i<=m;i++)    //读取m个桥的信息
       {
    	  Bridge bdg=new Bridge();
    	   bdg.a=sc.nextInt();
    	   bdg.b=sc.nextInt();
    	   bdg.t=sc.nextInt();
    	   blist.add(bdg);
       }	
       System.out.println(blist);//这一条是测试语句
       
        sort(blist);   //按天数排序   blist传给参数blist2后,不知道能不能实现排序的目的??
       //传参行不行???????
//       Collections.sort(blist,new Comparator<Bridge>(){
//			//override
//			public int compare(Bridge o1,Bridge o2){
//				return o2.t-o1.t;
//			}
//		});
       System.out.println(blist);
       init(n);   //先把小岛孤立的初始化为分散的并查集
       
       int a=-1;  //a用来判断前后抗议的天数是不是在同一天
       int sum=0; //sum用来表示抗议的天数
       for(int i=0;i<m;i++)  //倒叙得到m个桥,jingxing合并。合并时并查集-1,则抗议+1
       {   //得到第i个桥梁,它可以把两个小岛合并
    	  int b= mergee(blist.get(i).a,blist.get(i).b);    //把桥两端的岛屿合并
    	   
    	 if(b==1)//如果不属于一个集合而合并成功为一个集合
    	 {
    		 if(blist.get(i).t!=a)//与上一个抗议的日期不在同一天
    		 {sum++;
    		 a=blist.get(i).t;
    		 }
    	 }
       }
       
       System.out.println("sum="+sum);
       
	}

	
	
	//把桥按照天数逆序排序,逆向思维进行建立桥梁  每当建立一个桥梁,集合减少,说明没有这所桥梁时,
	//有两个孤立的集合存在,那么老百姓无法过桥到另外一座岛屿上,则老百姓在抱怨
	// 传参可
	private static void sort(ArrayList<Bridge> blist2) {
		Collections.sort(blist2,new Comparator<Bridge>(){
			//override
			public int compare(Bridge o1,Bridge o2){
				return o2.t-o1.t;
			}
		});
	}
	
	//




	private static int mergee(int x,int y) {   //并查集把有关系的和并在一起
		// TODO Auto-generated method stub
		x=findx(x);
		System.out.println(x);
		y=findx(y);
		System.out.println(y);
		if(x!=y)
			{s[x]=y;
			return 1;//return 1说明本来是不连通的(不在一个集合中的)
			}
		else 
			return 0;//return 0说明本来是在一个集合中的
	}

	
	private static int findx(int x)   //并查集查询并优化
	{  if(x!=s[x])
		  s[x]=findx(s[x]); //查询并优化
	   return s[x];
	}

	public static void init(int n)  //并查集初始化
	{
		for(int i=1;i<=n;i++)
		{s[i]=i;       //s[]是并查集的基本数据结构
	System.out.println("s[i]"+s[i]);
		}
			
	}
	
	
	
}




class Bridge{
	//Bridge是个对象   a,b, 是桥连接的小岛的号。t是 天数
	 public int a,b,t;
	public Bridge(){
		
	}
	public Bridge(int a,int b,int t)
	{this.a=a;
	this.b=b;
	this.t=t;}
	
	public String toString()
	{return a+" "+b+" "+t;}
	
}

4.

总结:

首先,该程序中用到了 并查集的概念。并妥善使用了初始化,查询,合并的功能。

其次,该程序中用到了ArrayList来表示有序集合元素,比数组要好用一些。

再次。用到了Collections的sort功能。它可以对一个列表进行排序,且列表中的元素是对象,然后按照对象中的某一项的大小进行比较,采用降序的形式,排序效果好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值