声明:快速求和有两道题目,第一题是一般的题目类型,而第二道题目则是数据加强版,数值变大,可能会出现卡死,或时间超限,内存超限的状况,但这在代码中都有优化体现,以达到提升速度,优化程序的目的。
一、快速求和
时间限制: 10 Sec
内存限制: 256 MB
题目描述
给定一个数字字符串,用最少次数的加法让字符串等于一个给定的目标数字。每次加法就是在字符串的某个位置插入一个加号。在需要的所有加号都插入后,就象做普通加法那样来求值。 例如,考虑字符串”12”,做0次加法,我们得到数字12。如果插入1个加号,我们得到3。因此,这个例子中,最少用1次加法就得到数字3。 再举一例,考虑字符串”303”和目标数字6,最佳方法不是”3+0+3”,而是”3+03”。能这样做是因为1个数的前导0不会改变它的大小。 写一个程序来实现这个算法。
输入
第1行:1个字符串S(1<=length(S)<=20)和1个整数N(N<=2^9-1)。S和N用空格分隔。
输出
第1行:1个整数K,表示最少的加法次数让S等于N。如果怎么做都不能让S等于N,则输出-1。
样例输入
2222 8
样例输出
3
提示
二、[CQOI1143]快速求和 数据加强版
时间限制: 1 Sec
内存限制: 128 MB
题目描述
给定一个数字字符串,用最少次数的加法让字符串等于一个给定的目标数字。每次加法就是在字符串的某个位置插入一个加号。在需要的所有加号都插入后,就象做普通加法那样来求值。 例如,考虑字符串”12”,做0次加法,我们得到数字12。如果插入1个加号,我们得到3。因此,这个例子中,最少用1次加法就得到数字3。 再举一例,考虑字符串”303”和目标数字6,最佳方法不是”3+0+3”,而是”3+03”。能这样做是因为1个数的前导0不会改变它的大小。 写一个程序来实现这个算法。
输入
第1行:1个字符串S(1<=length(S)<=40)和1个整数N(N<=10^5)。S和N用空格分隔。
输出
第1行:1个整数K,表示最少的加法次数让S等于N。如果怎么做都不能让S等于N,则输出-1。
样例输入
2222222222222222222222222222222222222222 80
样例输出
39
提示
【代码】解析
无疑,此题可以用三种方法来做:①搜索 ②记忆化搜索 ③DP 在面对超时等情况时,②③种方法都可以使用。用搜索,也就是一个枚举的过程,再用上一个数组,或再减一下枝,这道题就可以顺利的解出来了。详情请见代码。
①DP
正在思考中,闭关修炼。。。char int bool float long double
②搜索+剪枝
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cmath>
using namespace std;
char a[225];
bool vis[225];
int f[225][225],k,lena;
int minl=INT_MAX;;
#define INTMAX 100000000
void dfs(int i,int last,int num,int He)//位置,上个加号,加号数量,和
{if(He+f[last+1][i]>k) return;if(num>=minl) return; //最优性剪枝if(i==lena) {He+=f[last+1][lena];if(He==k)if(num<minl) minl=num; return ;}dfs(i+1,last,num,He);int j=f[last+1][i];dfs(i+1,i,num+1,He+j);
}
int main()
{scanf("%s",a);scanf("%d",&k);lena=strlen(a);for(int i=0;i<lena;i++)f[i+1][i+1]=a[i]-'0';for(int i=1;i<lena;i++)for(int j=i+1;j<=lena;j++){f[i][j]=f[i][j-1]*10+f[j][j];if(f[i][j]>INTMAX) f[i][j]=INTMAX;}dfs(1,0,0,0);if(minl<lena)printf("%d",minl);else printf("-1");
}
③记忆化搜索
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cmath>
using namespace std;
char a[45];
int f[45][45],memo[45][100005],k,lena;
#define INTMAX 100000000
int Dp(int i,int goal)
{int t,next,minp=INTMAX;if(i>lena){if(goal==0)return 0;elsereturn INTMAX;}if(memo[i][goal]!=-1) return memo[i][goal];int &ans=memo[i][goal];for(int j=i;j<=lena;j++){t=f[i][j];if(t>goal) break;next=Dp(j+1,goal-t);if(next<minp) minp=next;}if(minp<INTMAX) ans=minp+1;else ans=INTMAX;return ans;
}int main()
{scanf("%s",a);scanf("%d",&k);lena=strlen(a);memset(memo,-1,sizeof(memo));for(int i=0;i<lena;i++)f[i+1][i+1]=a[i]-'0';for(int i=1;i<lena;i++)for(int j=i+1;j<=lena;j++){f[i][j]=f[i][j-1]*10+f[j][j];if(f[i][j]>INTMAX) f[i][j]=INTMAX;}int tu=Dp(1,k);if(tu==INTMAX)printf("-1");else printf("%d",tu-1);
}