当前位置: 代码迷 >> 综合 >> 【八中】快速求和(1143 [CQOI1143])
  详细解决方案

【八中】快速求和(1143 [CQOI1143])

热度:95   发布时间:2023-11-27 22:55:56.0

声明:快速求和有两道题目,第一题是一般的题目类型,而第二道题目则是数据加强版,数值变大,可能会出现卡死,或时间超限,内存超限的状况,但这在代码中都有优化体现,以达到提升速度,优化程序的目的。

一、快速求和

时间限制: 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);
}