1143 快速求和

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34283998/article/details/78757862

1143 快速求和

题目描述

给定一个数字字符串,用最少次数的加法让字符串等于一个给定的目标数字。每次加法就是在字符串的某个位置插入一个加号。在需要的所有加号都插入后,就象做普通加法那样来求值。 例如,考虑字符串”12”,做0次加法,我们得到数字12。如果插入1个加号,我们得到3。因此,这个例子中,最少用1次加法就得到数字3。 再举一例,考虑字符串”303”和目标数字6,最佳方法不是”3+0+3”,而是”3+03”。能这样做是因为1个数的前导0不会改变它的大小。 写一个程序来实现这个算法

分析

Dp

d[i][k]表示前i个数中凑到k的最少加号数。
g[i][j]表示第i位到第j位形成的数,可以预处理出来。
枚举前一个加号的位置j,然后转移到d[i][k+g[j+1][i]]形成递推。

d[i][k+g[i+1][i]]=min(d[i][k+g[i+1][i]],d[j][k]+1);
注意:
1. 由于第一个数之前是没有加号的,所以k要从0开始枚举。
2. 问题解决完了数的最后会多出一个加号来,所以ans要-1.
3. 我的代码实现中并没有直接枚举前一个加号的位置,而是枚举大小,减过去的。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define MAXN 100
    #define MAXM 1024
    #define INF 0x3fffffff
    using namespace std;

    int n,len,ans=INF;
    int g[MAXN+5][MAXN+5];
    int d[MAXN+5][MAXM];

    int main()
    {
        for(int i=0;i<=MAXN;i++)
            for(int j=0;j<=MAXM;j++)
                d[i][j]=INF;
        char s[50];
        scanf("%s%d",s,&n);
        len=strlen(s);
        for(int i=1;i<=len;i++)
            g[i][i]=s[i-1]-'0';
        for(int i=1;i<len;i++)
            for(int j=i+1;j<=len;j++)
            {
                g[i][j]=g[i][j-1]*10+g[j][j];
                if(g[i][j]>INF)
                    g[i][j]=INF;
            }
        d[0][0]=-1;
        for(int i=1;i<=len;i++)
            for(int j=1;j<=i;j++)
            {
                if(g[i-j+1][i]>n)
                    break;
                for(int k=0;k<=n;k++)
                    if(d[i-j][k]!=INF)
                    {
                        if(k+g[i-j+1][i]>n)
                            break;
                        d[i][k+g[i-j+1][i]]=min(d[i][k+g[i-j+1][i]],d[i-j][k]+1);
                    }
            }
        printf("%d",d[len][n]==INF?-1:d[len][n]);
    }

搜索

此题亦可搜索,同样处理出数组g。同样要考虑上一个加号的位置。所以搜索时的参数可以为:
i(位置),last(上一个加号的位置),p(已用加号个数),sum(当前凑到的和)。
数据小可以水过去,但如果数据大了,有以下剪枝供参考:
1. 可行性剪枝:当前的sum已经比n要大了,退出
3. 最优性剪枝:凑到当前的sum比n要小,但是p已经大于的记录的最佳值,退出
4. 可行性剪枝:当前的凑到的sum加上之后所有数合起来的值(即之后不加任何加号所形成的数)比n要小,退出

    void dfs(int i,int last,int p,int sum)
    {
        if(i==len)
        {
            sum+=g[last+1][len];
            if(sum==n)
                if(p<ans)
                    ans=p;
            return ;
        }
        dfs(i+1,last,p,sum);
        int j=g[last+1][i];
        dfs(i+1,i,p+1,sum+j);
    }

猜你喜欢

转载自blog.csdn.net/qq_34283998/article/details/78757862
今日推荐