java实现好玩的石子游戏——蓝桥入门

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
  石子游戏的规则如下:
  地上有n堆石子,每次操作可选取两堆石子(石子个数分别为x和y)并将它们合并,操作的得分记为(x+1)×(y+1),对地上的石子堆进行操作直到只剩下一堆石子时停止游戏。
  请问在整个游戏过程中操作的总得分的最大值是多少?
输入格式
  输入数据的第一行为整数n,表示地上的石子堆数;第二行至第n+1行是每堆石子的个数。
输出格式
  程序输出一行,为游戏总得分的最大值。
样例输入
10
5105
19400
27309
19892
27814
25129
19272
12517
25419
4053
样例输出
15212676150
数据规模和约定
  1≤n≤1000,1≤一堆中石子数≤50000

拿到这个问题,我第一反应就是用集合。因为数组一旦建立,长度就固定了,合并起来会非常麻烦。这个问题的入手点还是挺简单的,求分公式已经告诉了:(x+1)*(y+1),既然是求总得分的最大值,那么只需每次都找石子数最多的两堆石子合并,得分一定是最多的。因此题目关键点在于如何找出一组数据中2个的最大的数。
关于找这俩最大的数,笔者走了点弯路。一开始是这样写的:

 static void countScores(List<Long> list) {  //计分操作
    	if(list.size()==1) {    
    		return;             	//如果只剩一堆石子,结束递归
    	}
    	//找出块数最多的两堆石子
    	long max1=0;    //块数最多的
    	long max2=0;    //块数第二多的
    	int u=0;          //u、v用于记录下标
    	int v=0;
    	for(int i=0;i<num.size();i++) {
    		if(max1<=num.get(i)) {    //如果还有块数更多的
    			max2=max1;                //当前第二多=原先最多
    			v=u;                               //下标也换过来
    			max1=num.get(i);      
    			u=i;
    		}else if(max2<num.get(i)) {
    			max2=num.get(i);
    			v=i;
    		}
    	}
    	merge(max1, max2, u, v);  //合并最多的两堆石子
    	maxScore=maxScore+(max1+1)*(max2+1);   //记录得分
    	countScores(num);	
    }

虽然测试也通过了,但是不是觉得太麻烦?每次都要比较出找最大的两个数,还要记录下标。而且递归方法中套着for循环,算法复杂度也比较高。笔者虽然很菜,但上进心还是有的^ _ ^。不安于现状的我于是开始探寻优化方案。
经过一番思索和资料的搜集,终于有了新点子:先排序!排序的好处是处理合并过程的时候方便得多,每次只要合并集合中最后两个石堆就好了,因为最后两个一定是最大的两个。二次测试,果然看到了优化效果:在这里插入图片描述
这里还要感谢这位朋友的博客给我的启发:点此链接可查看https://blog.csdn.net/weixin_43887915/article/details/105013845
最后,附上全部的源码吧,不足之处希望有大佬及时指正,感激不尽呀~~

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

public class StoneGame2 {
	static List<Long> num; // 用于存放各堆石子块数
	static long maxScore = 0; // 最大得分,范围用long型
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		num=new ArrayList<Long>();
		for(int i=0;i<n;i++) {
			num.add(sc.nextLong());
		}		
		sc.close();
		//排一下序更方便操作,可以先借助java的API自带方法,也可以自己写一个排序
		Collections.sort(num);   
		countScores(num);			//计分操作
		System.out.println(maxScore);
	}
	
	//可以用递归或者while循环
	static void countScores(List<Long> list) {
		if(list.size()==1) {    
    		return;             	//如果只剩一堆石子,结束递归
    	}
    	//由于已经排序,集合最后两个位置的数一定是最大的两个
       long max1=list.get(list.size()-1);
       long max2=list.get(list.size()-2);
    	maxScore=maxScore+(max1+1)*(max2+1);   //记录得分
    	//将两个石块最多的石堆合为一个石堆,先删除旧的后添加新的
    	list.remove(list.size()-1);  
    	list.remove(list.size()-1);   //两次都是删掉最后一个
    	list.add(max1+max2);
    	countScores(num);
	}
}

ps:取值范围很重要!数据相加后很容易超过int所表示的最大长度(10位),因此要用long型!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dijkstra's Monk-ey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值