快速求和
题目描述
给定一个数字字符串,用最小次数的加法让字符串等于一个给定的目标数字。每次加法就是在字符串的某个位置插入一个加号。在里面要的所有加号都插入后,就像做普通加法那样来求值。
例如,考虑字符串12
,做 \(0\) 次加法,我们得到数字 \(12\)。如果插入 \(1\) 个加号,我们得到 \(3\),因此,这个例子中,最少用 \(1\) 次加法就得到数字 \(3\)。
再举一例,考虑字符串303
和目标数字 \(6\),最佳方法不是3+0+3
。而是3+03
。能这样做是因为一个数的前导 \(0\) 不会改变它的大小。
输入格式
第一行:一个字符串 \(s\)。
第二行:一个整数 \(n\)。
输出格式
一行一个整数表示最少的加法次数让 \(s\) 等于 \(n\)。如果怎么做都不能让 \(s\) 等于 \(n\) ,则输出 \(-1\)。
样例 #1
样例输入 #1
99999
45
样例输出 #1
4
提示
数据规模与约定
对于 \(100\%\) 的数据,保证 \(1\le \operatorname{len}(s)\le40\),\(1 \leq n\le10^5\)。
解析
这道题的解析好像也没啥可说的,就是爆搜+剪枝就可以过了,读入时将字符转化为数值方便处理,搜索时有两种情况,在该位置加上加号和不加加号,不断向下搜。
代码
#include <bits/stdc++.h>
using namespace std;
string s;
int a[50], res = 0x3f3f3f3f, len, n;
void dfs(int step, int ans, int sum, int now) {
//step表示当前处理的位数,ans是加号数
//sum是最后一个加号前的总和,now表示还在累加的值(加号还未确定)
if (ans > res || sum > n || now > n) return ;//剪枝
if (step > len) {
if (sum + now == n) res = ans;//更新答案
return ;
}
now = 10 * now + a[step];
dfs(step + 1, ans + 1, sum + now, 0);//添一个加号
dfs(step + 1, ans, sum, now);//不添加号
}
int main() {
cin >> s >> n;
len = s.length();//字符串长度
for (int i = 1; i <= len; i ++) a[i] = s[i - 1] - '0';//取出每一位,转成数值
dfs(1, 0, 0, 0);//从第一位开始搜索
if (res >= len) cout << -1 << '\n';
else cout << res << '\n';
return 0;
}