第十二届蓝桥杯JavaB组省赛-砝码称重

本文介绍了一道Java编程题,涉及砝码称重的动态规划解决方案。作者通过两个版本的代码展示了如何避免重复计算,利用HashSet特性优化效率。在第一个版本中,使用LinkedList存储中间结果以防止错误的重复计算;在第二个版本中,简化了条件判断,直接利用HashSet的不可重复性提高性能。最后,作者分享了优化后的代码并表达了全部AC的喜悦。
摘要由CSDN通过智能技术生成

题目

在这里插入图片描述

主要思路

首先,上来第一眼看是一个很简单的排列组合问题,但是暴力算法肯定是超时的。废话不多说,上代码。

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
public class Main {
	
	public static void main(String[] args) 
	{
		Scanner in =new Scanner(System.in);
		int N,i,temp,tt;
		N=in.nextInt();        
		int[] num=new int[N];
		for ( i = 0; i < N; i++) 
			num[i]=in.nextInt();
		Set<Integer> contain =new HashSet<>();
		List<Integer> a =new LinkedList<>();        //存放中间变量,一次遍历中,容器不存在 的数
		contain.add(Integer.valueOf(num[0]));     //先将第一个元素填入到容器
		for(i=1;i<N;i++)
		{
			for (Iterator<Integer> iter =contain.iterator();iter.hasNext();) {
				tt=iter.next().intValue();
				temp=tt+num[i];
				if(temp!=0&&temp<100000&&!contain.contains(Integer.valueOf(temp)))
					a.add(Integer.valueOf(temp));
				temp=tt-num[i];
				temp=Math.abs(temp);   //砝码差的绝对值
				if(temp!=0&&temp<100000&&!contain.contains(Integer.valueOf(temp))&&!a.contains(Integer.valueOf(temp)))
						a.add(Integer.valueOf(temp));
			}
			contain.addAll(a);
			a.clear();
			if(!contain.contains(Integer.valueOf(num[i])))
				contain.add(Integer.valueOf(num[i]));
		}
		System.out.println(contain.size());
	}
}

记录一下自己第一次全部AC,可能有更好的思路,但是下面还是讲一下我的思路吧!

思路

首先,对于这种需要很多组合的问题,肯定是动态规划了。首先将第一个砝码放入右边,目前只有一种组合。继续放入第二个砝码,你可以选择继续放到右边或者左边。放入右边其实逻辑上就是砝码A+砝码B,放入左边就是砝码A-砝码B结果的绝对值。剩下的就是重复一直放入砝码。
在代码实现中,我选择的数据结构是HashSetLinkedList。HashSet用于存放加完砝码的结果。而LinkedList用于存放加砝码时的不确定砝码值。
为什么不直接将加完的值全放进HashSet中,非得加一个LinkedList。因为如果直接加入,那么就对上一次的砝码称重的结果,造成了影响。意思就是,你刚加出来的结果,有会被踢出去,被这个重量的砝码再运算一次。
例如:

HashSet : 1 2 4

这次要加入的砝码是 6
首先1 + 6 = 7

那么HashSet: 1 2 4 7

到最后 7 + 6 = 13

HashSet: 1 2 4 7 13

实际上,这里的6用了两次,你把用这次砝码6运算出来的结果7,又加了一次6,变成了13.显然,这个结果是错误的。
我选择将一次迭代的结果,先放在LinkedList容器中,最终一并放入HashSet中.

第二次代码

import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class Main {
	
	public static void main(String[] args) 
	{
		Scanner in =new Scanner(System.in);
		int N,i,temp,tt;
		N=in.nextInt();        
		int[] num=new int[N];
		for ( i = 0; i < N; i++) 
			num[i]=in.nextInt();
		Set<Integer> contain =new HashSet<>();
		Set<Integer> a =new HashSet<>();        //存放中间变量,一次遍历中,容器不存在 的数
		contain.add(Integer.valueOf(num[0]));     //先将第一个元素填入到容器
		for(i=1;i<N;i++)
		{
			for (Iterator<Integer> iter =contain.iterator();iter.hasNext();) {
				tt=iter.next().intValue();
				temp=tt+num[i];
				if(temp!=0&&temp<100000)
					a.add(Integer.valueOf(temp));
				temp=tt-num[i];
				temp=Math.abs(temp);
				if(temp!=0&&temp<100000)
						a.add(Integer.valueOf(temp));
			}
			contain.addAll(a);
			a.clear();
			if(!contain.contains(Integer.valueOf(num[i])))
				contain.add(Integer.valueOf(num[i]));
		}
		System.out.println(contain.size());
	}
}

最新的改进:
很明显if语句中的限制条件变少了。因为我运用HashSet的性质,无序、不可重复。使用两个HashSet,每次运算的结果。不用再判断在原来出现过!直接将所以的结果都加入,如果重复会直接加入失败。
第一版本的代码是用
contains( )方法
去判断,是否在原来的容器中出现,HashSet对于查找效率很高,使用HashSet直接添加,他会先查找是否先前存在该值,明显的HashSet查找的效率会快于contains( )方法

在这里插入图片描述
全部AC的感觉太棒了!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值