P1874 fast sum (DFS&&DP)

Posted by mgurain on Fri, 27 Dec 2019 17:06:09 +0100

Title Description

Given a number string, add the minimum number of times to make the string equal to a given target number. Each addition is to insert a plus sign somewhere in the string. After all the plus signs in it are inserted, they are evaluated just like ordinary addition.

For example, consider the string "12", add 0 times, and we get the number 12. If we insert a plus sign, we get 3, so in this case, we get the number 3 by adding at least once

For another example, considering the string "303" and the target number 6, the best method is not "3 + 0 + 3". It's "3 + 03.". This can be done because the leading 0 of a number does not change its size.

Write a program to implement the algorithm.

I / O format

Input format:

 

Line 1: 1 string s (length of 1 < = s < = 40);

Line 2: 1 integer n (n < = 100000).

 

Output format:

 

Line 1: an integer K, indicating that the minimum number of addition times makes S equal to n. If nothing can be done to make S equal to N, output - 1

 

Example of input and output

Input example ා 1:copy

99999
45

Output example:copy

4

 

Explanation:
At first, I thought about violent solution, but I found that since the code could not be written, I thought about dfs

Let me start with the dfs Code:
 

#include <iostream>

using namespace std;
string s;
int n, ans = 1000, maxplus;
int a[50];
bool flag = 0;
int turn(int start, int end) {          //Return from value record of a + b
	int sum = 0;
	for(int i = start; i <= end; ++i)
		sum *= 10,sum += a[i];
	return sum;
}
void dfs(int now, int step, int cntplus) {  //Current value current plus sign position current plus sign quantity
	if(cntplus > maxplus)  return;       //Stop when found, and stop when the plus sign is greater than the maximum number
	if(now == n)  {                              // Find all stop
		flag = 1;
		ans = min(ans,cntplus);
		return;
	}
	for(int i = step + 1; i < s.size(); ++i)           //Look for it later
		dfs(now + turn(step + 1, i),i,cntplus + 1);
}
int main() {
	cin >> s >> n;
	for(int i = 0; i < s.size(); i++) {
		a[i] = s[i] - '0';
	}
	maxplus = s.size() - 1;                                             //Maximum number of plus signs 
	for(int i = 0; i < s.size() - 1; ++i)  dfs(turn(0,i), i, 0);    //The first plus digger has a special situation of 00000
	if(flag )  cout << ans ;
	else cout << -1 ;
	return 0;
}

It's hard not to pass three test cases.

Here's the dp Code: in special cases, there are two groups

0000 0                        222 0

//The minimum addition times of the first i-digit component j f[i][j] = min {f [i-k] [j-s [i-k + 1], f[i][j]}

The explanation code is very detailed.

#include <iostream>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f, maxn = 100001;
int n, a[41], dp[42][maxn], sum[42][42] = {0};// The minimum addition times f [i] [j] = min {f [i-k] [j-s [i-k + 1]
string s;
int main() {
	cin >> s;
	int len = s.size();
	for(int i = 0; i < len; i ++) a[i + 1] = s[i] - '0';
	for(int i = 1; i <= len; i++) {
		sum[i][i] = a[i];
		for(int j =i + 1; j <= len; j++)
			sum[i][j] += sum[i][j - 1] * 10 + a[j];        //sum represents the value from i to j
	}
	cin >> n;
	if(!n&&!sum[1][len]) return cout << 0,0;
	memset(dp, 0x3f, sizeof(dp)),dp[0][0] = 0;           
	for(int i = 1; i <= len; i++)
		for(int k = 1; k <= len && k <= 6; k++)            
			if(k <= i)                               //k < i
				for(int j = sum[i - k +1][i]; j <= n; j++)
					dp[i][j] = min(dp[i-k][j-sum[i-k+1][i]] + 1,dp[i][j]);   //Minimum steps from dp to i to j
	if(dp[len][n] == INF) cout << -1 ;
	else cout << dp[len][n] - 1;
	return 0;
}