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

来源:互联网 发布:淘宝代购点 编辑:程序博客网 时间:2024/05/01 16:14

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

一、快速求和

时间限制: 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 100000000void 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 100000000int Dp(int i,int goal){    int t,next,minp=INTMAX;    if(i>lena)    {        if(goal==0)            return 0;        else            return 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);}