P1249 最大乘积(Java高精度乘法)

题目描述

一个正整数一般可以分为几个互不相同的自然数的和,如 3 = 1 + 2 3=1+2 3=1+2 4 = 1 + 3 4=1+3 4=1+3 5 = 1 + 4 = 2 + 3 5=1+4=2+3 51+4=2+3 6 = 1 + 5 = 2 + 4 6=1+5=2+4 6=1+52+4

现在你的任务是将指定的正整数 n n n 分解成若干个互不相同的自然数的和,且使这些自然数的乘积最大。

输入格式

只一个正整数 n n n,( 3 ≤ n ≤ 10000 3 \leq n \leq 10000 3n10000)。

输出格式

第一行是分解方案,相邻的数之间用一个空格分开,并且按由小到大的顺序。

第二行是最大的乘积。

样例 #1

样例输入 #1

10

样例输出 #1

2 3 5
30

1.题目分析

输入一个最小为3的整数,拆分为若干个自然数之和,并且自然数不能相同,求拆分后各个元素的最大乘积。

这道题涉及到了所谓的贪心算法,其实就是一种思想,使某一个问题的结果尽可能多和大。

这里做几点提示:

  • 要是乘积最大,则起码要从2开始拆分,所以我们简单写几组样例:
当输入3时,结果为:1 2
当输入4时,结果为:1 3
当输入5时,结果为:2 3
当输入6时,结果为:2 4
当输入7时,结果为:3 4
当输入8时,结果为:3 5
当输入3时,结果为:2 3 4

不难发现,除了3和4,其他情况都是不包含1的,最小自然数也是要大于等于2的。

  • 那么我们排开3和4之后,就只需要讨论其他情况:从2开始累加,直到大于N,累加和超过N的部分有两种情况:第一,刚好超过了1,那么我们只需要让最大的数减一,让2归零,就实现了总体减1的结果。第二,超过N的部分大于1:那么超过部分的数肯定是在这些统计的自然数中的,直接让其置零即可。
  • 最后这道题还涉及到了高精度乘法,所以本人也想用c++写的,奈何Java的 BigInteger(这里附上使用方法)实在太好用了。

2.题目思路

1.输入

输入一个整数n,定义一个数组存储分解后的自然数,

2.特判3

对3的情况进行特判:让数组的0索引为1。

3.统计自然数组

从2开始循环累加数组,并记录自然数的值,当累加和刚好超过n时跳出循环,并记录最大自然数的索引。

4.对自然数的数据进行清洗

判断累加和大于N的情况:
当刚好差值为1时:将最大索引处的元素加一,元素2清零,
如果恰好最大索引处加一为N时,
比如:输入4 这一步应该得到 2 3 -> 0 4,则零索引置为1,最大索引处元素又减一。

其他差值超过大于1的情况,直接把超过的大小对应的数剔除即可。

5.高精度累乘

累乘:将数组中不为0的元素累乘,调用的大数乘法,边乘边打印非零元素。

6.输出

最后换行,输出结果即可。

3.代码实现

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        //输入一个整数
        int n = sc.nextInt();
        //存储分解后的自然数
        int[] arr = new int[10000];
        //求和
        int sum = 0;
        //分解后的最大自然数的索引
        int index = 0;
        //大数的连乘结果
        BigInteger multiple = BigInteger.valueOf(1);
        //对3进行特判:索引0处补1
        if (n == 3) {
            arr[0] = 1;
        }
        for (int i = 2; i < n; ++i) {
            sum += i;
            arr[i] = i;
            //累加自然数,当刚好超过n时跳出
            if (sum >= n) {
                //加数的最大索引
                index = i;
                break;
            }
        }
        //计算累加和超出N的部分
        int differ = sum - n;
        //求最优解
        if (sum > n) {
            //当刚好只超过了1时
            if (differ == 1) {
                //将最大索引处的元素加一,元素2清零
                arr[2] = 0;
                arr[index]++;
                //如果刚好最大索引处加一为N时,比如:输入4 这一步应该得到 2 3 -> 0 4
                if (arr[index] == n) {
                    //即应该处理为:1 3
                    //值得一提的是:包含1的情况也只有输入3 和 4而已
                    arr[0] = 1;
                    arr[index]--;
                }
            } else {
                //其他超过大于1的情况,直接把超过的大小对应的数剔除即可。
                arr[differ] = 0;
            }
        }
        //将数组中不为0的元素累乘
        for (int i = 0; i < n; ++i) {
            if (arr[i] != 0) {
                //这里调用的大数乘法
                multiple = multiple.multiply(BigInteger.valueOf(arr[i]));
                //边乘边打印非零元素
                System.out.print(arr[i] + " ");
            }
        }
        //换行
        System.out.println();
        //打印结果
        System.out.println(multiple);
    }
}

你可能感兴趣的:(刷题go,go,go,java,开发语言,算法)