[编程题]石头碰撞

快手Java工程师笔试题

问题描述

**给定一组石头,每个石头有一个正数的重量。每一轮开始的时候,选择两个石头一起碰撞,假定两个石头的重量为x,y,x<=y,碰撞结果为

  1. 如果x==y,碰撞结果为两个石头消失
  2. 如果x != y,碰撞结果两个石头消失,生成一个新的石头,新石头重量为y-x
    最终最多剩下一个石头为结束。求解最小的剩余石头质量的可能性是多少。**

输入描述:
第一行输入石头个数(<=100)
第二行输入石头质量,以空格分割,石头质量总和<=10000
输出描述:
最终的石头质量

算法分析

根据分析可知,要求的最少剩余石头质量问题。可以考虑到是0-1背包问题。由两两石头相撞,可以考虑把石头分成两堆,两堆石头之间进行碰撞,如何分堆使碰撞之后石头最小的问题。两堆石头的总质量之和为sum,则两堆石头中质量最小的那堆的质量肯定不超过sum/2。为了使最终结果最小即两堆石头的质量之差最小,即求最小这堆石头的最大质量,当它最大质量为sum/2时,两堆石头相撞为0。

下面即求最小堆V1质量最大的问题,即0-1背包问题。从n个石头中挑选出最合适的组合使V1最大,且V1<=sum/2的问题。

具体代码如下
import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] v = new int[n];
        //计算出所有石头的总质量
        int sum = 0;
        for (int i = 0; i < n; i++) {
            v[i] = sc.nextInt();
            sum+= v[i];
        }
        int arevge = sum/2;
        //利用boolean数据记录石头组合的状态可能性
        boolean[] status = new boolean[arevge + 1];
        status[0] = true;
        for (int i = 0; i < n; i++) {
            for (int j = arevge; j >= v[i]; j--) {
                //如果前面有组合使最小堆V1的质量等于status[j - v[i]]即值为true,则j - v[i]为true,则j - v[i]加上当前这块石头质量v[i]仍满足仍为true,则status[j] = true.
                status[j]|= status[j - v[i]];
            }
        }
        //利用循环挑选出能使最小堆V1最大的值
        for (int i = arevge; i > 0; i--) {
            if (status[i]) {
                System.out.println(sum - i - i);
                return;
            }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

咖飞_coffee

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

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

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

打赏作者

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

抵扣说明:

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

余额充值