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();
}
}