【问题标题】:Not getting proper result with my recursion for quick sum recursion我的递归没有得到正确的结果以进行快速总和递归
【发布时间】:2015-04-06 11:59:31
【问题描述】:

给定一串数字,找出该字符串等于某个目标数字所需的最小加法数。每次添加都相当于在数字字符串的某处插入一个加号。

示例: “1110”

目标 3

将 3 返回为 1+1+1+0=3 需要 3 次加法。

“0123456789”

目标 45

返回:8

“99999”

目标 100

返回:-1

“382834”

100

返回:2

获得 100 的方法有 3 种,分别是 38+28+34、3+8+2+83+4 和 3+82+8+3+4。最低要求是 2。

我试过这个问题,这是我的代码。我第一次考虑一个角色并得到结果。下次我使用 2 个字符并获得结果等等,直到我尝试了所有字符,直到字符串的大小。我没有得到正确的递归。

    int min(int a,int b)
    {
        return a>b?b:a;
    }

    /* i is current index we are considering and sum is total number
     *of + required
     */
    int foo(char *a, int size, int i, int current_stock, int target, int sum){
        unsigned long long int mini = 1 << 30; /* huge number */
        int number=0, mul, m;
        int p = i;
        if (i+current_stock>size)
            return mini;
        if (target == 0)
            return sum;
        if (target < 0)
            return mini;
        mul = 1;
        /* make the multiplier */
        for (m=1;m<current_stock;m++) {
            mul *= 10;
        }
        /* make the number from i to current_stock
         * if the string is 123 and if i is 0 and current_stock is 2
         * then the number will be 12 */
        for (m=0;m<current_stock;m++) {
            number += (a[p]-'0')*mul;
            mul = mul/10;
            p++;
        }

        sum = sum + 1;
        for(m=current_stock;m<=size;m++) {
            mini = min(mini, foo (a, size, i+current_stock, m, target-number, sum));
        }
        return mini;
    }

    int main(void) {
        char a[] = "382834";
        printf("%d", foo(a, strlen(a), -1, 1, 100, 0));
        printf("%d\n", strlen(a));
        return 0;
    }

【问题讨论】:

    标签: algorithm recursion dynamic-programming


    【解决方案1】:

    我编写了您提到的确切解决方案,它似乎对我有用。只是一个变化,你不需要走到所有的角色,如果你已经越过了目标,那么可以提前打破。

    #define INFINITY 100000
    long int result[20][1000];
    
    long int solve(char *str,long int i,long int target){
        long int min=INFINITY;
        long int number=0,base=10;
        long int j=i;
        long int score1;
        //memoized result
        if(result[i][target]!=-2){
            return result[i][target];
        }
    
        //if target is achieved and string is finished
        if(i==strlen(str) && target==0){
            return 0;
        }
        // if string finished but target not achieved
        if(i==strlen(str)&& target!=0){
            return -1;
        }
    
        while(j<strlen(str)){
            long int digit=str[j]-'0';
            number=number*base+digit;
            if(number <=target){
                score1=solve(str,j+1,target-number);
                if(score1!=-1){
                    if(j<(strlen(str)-1))
                        score1=score1+1;
                    if(score1<min){
                        min=score1;
                    }
                }
            }
            else{
                break;
            }
            j++;
        }
        if(min<INFINITY)
            result[i][target]=min;
        else
            result[i][target] = -1;
        return result[i][target];
    }
    

    对于非计算值,我正在使用 -2 初始化我的记忆数组结果。我检查了所有给定的测试用例,它正在工作。请检查解决方案,让我知道它是否有意义。

    【讨论】:

    • 您的解决方案与我的几乎相似,因此我将其标记为正确的解决方案。 Gene 发布的解决方案是完美的,但由于您的解决方案与我的类似,我将其标记为正确答案。
    • @newbie_old 谢谢。顺便问一下,这是一个 spoj(或任何其他在线法官)的问题吗?如果可以,可以分享一下链接吗?
    【解决方案2】:

    我猜@Naman 让你找到了解决方案,但你工作太努力了。只需将第一个加号放在每个可能的位置,然后重复放置其余部分。基本情况是所有数字都等于目标。在这种情况下,所需的加号数为零。

    #include <stdio.h>
    #include <string.h>
    #define NO_SOLUTION (-1)
    
    int find_min_plusses(int target, char *digits, int n_digits) {
      int min = NO_SOLUTION, val = 0, i;
      for (i = 0; i < n_digits - 1; i++) {
        val = val * 10 + (digits[i] - '0');
        if (val > target) return min;
        int rest = find_min_plusses(target - val, digits + i + 1, n_digits - i - 1);
        if (rest != NO_SOLUTION && (min == NO_SOLUTION || rest + 1 < min))
          min = rest + 1;
      }
      val = val * 10 + (digits[i] - '0');
      return val == target ? 0 : min;
    }
    
    int main(int argc, char *argv[]) {
      int target;
      if (argc == 3) {
        if (sscanf(argv[1], "%d", &target) != 1) return 1;
        int min = find_min_plusses(target, argv[2], strlen(argv[2]));
        printf("%d\n", min);
      }
      return 0;
    }
    

    在这里你可以看到它运行。每一行都是一个电话。

    ./a.out 100 382834
    tgt=100,digits=382834,n_digits=6
    tgt=97,digits=82834,n_digits=5
    tgt=89,digits=2834,n_digits=4
    tgt=87,digits=834,n_digits=3
    tgt=79,digits=34,n_digits=2
    tgt=76,digits=4,n_digits=1
    tgt=4,digits=4,n_digits=1
    tgt=61,digits=34,n_digits=2
    tgt=58,digits=4,n_digits=1
    tgt=15,digits=834,n_digits=3
    tgt=7,digits=34,n_digits=2
    tgt=4,digits=4,n_digits=1
    tgt=62,digits=2834,n_digits=4
    tgt=60,digits=834,n_digits=3
    tgt=52,digits=34,n_digits=2
    tgt=49,digits=4,n_digits=1
    tgt=34,digits=34,n_digits=2
    tgt=31,digits=4,n_digits=1
    2
    

    【讨论】:

    • 非常狡猾的代码,它很完美,但这不是我在寻找与我的代码相似的代码时遇到的问题的解决方案。
    • @newbie_old 当然。可能是这样。我只是想让你知道你正在以一种相当迂回的方式解决问题。我的代码一点也不狡猾。这是安排递归的一种直接方式。
    猜你喜欢
    • 2019-09-14
    • 2022-01-14
    • 1970-01-01
    • 2023-03-29
    • 2015-08-27
    • 2021-10-07
    • 2020-06-17
    • 2018-02-14
    • 2023-02-12
    相关资源
    最近更新 更多