2023 睿抗机器人开发者大赛CAIP-编程技能赛-高职组(国赛)

RC-v4 加号放哪里

给定任一个正整数 N,我们要从它开始,经过一系列操作得到一个个位数。操作方法是在 N 的各位数字之间放置一个加号,然后执行这个加法计算,得到一个新的数字 N1,再对 N1 执行同样操作,得到 N2 …… 以此类推,直到最后得到的数字只有 1 位,则停止。
例如我们从 N=1234567890 出发,在 5 和 6 之间放置加号,计算 12345+67890=80235;然后在 0 和 2 之间放置加号,计算 80+235=315;然后在 1 和 5 之间放置加号,计算 31+5=36;最后在 3 和 6 之间放置加号,得到 3+6=9 而停止。这样我们通过 4 次计算得到了一个个位数 9。
本题就请你为任一给定的正整数计算:最少需要多少次加号放置可以得到个位数?
注意:加号必须放置在两个数字之间,不可放置在数字的首尾。

输入格式:

输入在一行中给出一个正整数 n(≤ pow(10, 20))。

输出格式:

在一行中首先输出将输入的整数变为个位数,需要放置加号的最少次数;随后输出最后得到的那个个位数。如果最后得到的个位数不唯一,输出最小的那个。
数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:
1234567890
输出样例:
3 9
思路:

DFS暴力:将n拆分成所有可能的两部分然后再求和,循环往复。不优化情况下会有2-3个点超时或者爆范围。

  • 取值范围优化:这里n取值 < pow(10, 20),超过了Java的long和C++的long long,处理办法也比较简单粗暴,超范围就用BigInteger处理,反之就用long来接收,这样可以解决范围超限的问题。对应到后续的代码,超范围 ->dfs()处理,不超->dfs2()处理。

  • 时间优化:最开始由于取值范围比较大,全程使用String类型保存num值,然后每次用subString()将num分成两段,想到用HashMap键值对记忆出现过的值,下次再碰到则比较times,谁出现的更早,效果一般。后续改成不超范围情况下long类型按位取。

    // num为值1,rightNum为值2
    long rightNum = 0;
    long basic = 1;
    while (num > 9) {
      // 每次取值1的最后一位,变成值2的首位
                rightNum += num % 10 * basic;
                num /= 10;
                basic *= 10;
    //            System.out.println(num + " " + rightNum);
                dfs2(num + rightNum, times + 1);
            }
    
完整代码
package raicom.R2023N2;

import java.io.*;
import java.math.BigInteger;
import java.util.Date;

/**
 * @author curry
 */
public class Q4 {
    public static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    public static long resTimes = Integer.MAX_VALUE, resNum = Integer.MAX_VALUE;

    public static void dfs(String sNum, int times) throws Exception {
        if (times > resTimes) {
            return;
        }
        for (int i = 0; i < sNum.length() - 1; i++) {
            BigInteger b1 = new BigInteger(sNum.substring(0, i + 1));
            BigInteger b2 = new BigInteger(sNum.substring(i + 1));
            String newNum = b1.add(b2).toString();
            if (newNum.length() <= 18) {
                dfs2(Long.parseLong(newNum), times + 1);
            } else {
                dfs(newNum, times + 1);
            }
        }
    }

    public static void dfs2(long num, int times) {
        if (times > resTimes) {
            return;
        }
        // 个位数 符合条件 判断是否记录
        if (num < 10) {
            if (times < resTimes) {
                resTimes = times;
                resNum = num;
            } else if (times == resTimes) {
                resNum = Math.min(resNum, num);
            } else {
                return;
            }
        }
        long rightNum = 0;
        long basic = 1;
        while (num > 9) {
            rightNum += num % 10 * basic;
            num /= 10;
            basic *= 10;
            dfs2(num + rightNum, times + 1);
        }
    }

    public static void main(String[] args) throws Exception {
        String sNum = in.readLine();
        if (sNum.length() <= 18) {
            dfs2(Long.parseLong(sNum), 0);
        } else {
            //        Date t1 = new Date();
            dfs(sNum, 0);

        }
        out.print(resTimes + " " + resNum);
        out.flush();
        out.close();
    }
}
  • 23
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值