C语言 如何用唯一的数字分割一个int

vfhzx4xs  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(178)

我使用这个算法来划分(1<<N)-1,给定N。这是代码:

void btrack(int k, int N, int sum, int used, int rep) {
    //if (k > (N + 1)) exit(-1);
    //printf("called with k = %d, N = %d, sum = %d, used = %d, rep = %d\n", k, N, sum, used, rep);
    
    if (sum == (1 << N) - 1) {
        printf("ended with %d \n", rep);
        return;
    }
    if ((sum > (1 << N) - 1) || (used & 1 << k))
        return;
    used |= (1 << k);

    for (int i = 1; i <= (1 << N) - 1; i++) {
        if (!(used & 1 << i))
            btrack(i, N, sum + i, used, rep * 10 + i);
    }
}

字符串
我不想要一个常规分区。分区中的数字必须是唯一的。快速示例:

N = 3 -> (1<<N)-1 = 7
the Valid answers are :
1 + 2 + 4 = 7
2 + 5 = 7
6 + 1 = 7
4 + 3 = 7
7 = 7

the likes of :
2 + 2 + 2 + 1 = 7
1 + 1 + 1 + 1 + 3 = 7
etc...
are all incorrect because some numbers are repeated


我以为我实现了这个逻辑,但结果令人失望。我有时得到的总和大于目标,和重复。
rep变量将保存用于求和的数字:1+2+31232+525
谢谢你

8iwquhpp

8iwquhpp1#

存在一些问题:

  • rep * 10 + i只能存储个位数。对于N=4,您不能表示1+152+14等。
  • used |= (1 << k);int类型的范围限制。对于大于4Nk可以大于30,因此1 << k将具有未定义的行为。

你的方法可能适用于N < 4,但对于更大的值需要更通用的方法。我建议使用数组。这个数组最多需要保存sqrt(1 << N)数字,因此1 << (N - 1)数字。

v440hwme

v440hwme2#

你错误地使用了变量k。这似乎是你试图测试的最后一个值。递归的本质是你试图把问题分解成更小的问题,所以如果你想避免重复,那么你永远不应该在递归调用中使用相同的值。
相反,开始在k+1处开始循环:

#include <stdio.h>

void btrack(int k, int N, int sum, int used, int rep) {
    if (sum == (1 << N) - 1) {
        printf("ended with %d \n", rep);
        return;
    }
    if ((sum > (1 << N) - 1) || (used & 1 << k))
        return;
    used |= (1 << k);

    for (int i = k+1; i <= (1 << N) - 1; i++) {
        btrack(i, N, sum + i, used, rep * 10 + i);
    }
}

int main() {
    btrack(0, 3, 0, 0, 0);
}

字符串
输出量:

ended with 124 
ended with 16 
ended with 25 
ended with 34 
ended with 7


现在,这一切都可以工作,直到你需要分区非常大的值。你的基数为10的rep值几乎立即变得无用,而你的used值用完了位。当你想真正 * 打印 * 一个结果时,你需要搜索一个由大部分零组成的位数组。
另一种解决方案是将路径存储在数组中。它可能看起来像这样(半健壮但有点天真):

int run_foo(int value, int sum_parts[], int max_count, int count)
{
    if (count + 1 >= max_count)
        return 0;

    // Loop over all potential next values
    for (int next = sum_parts[count] + 1; next <= value / 2; next++) {
        sum_parts[count + 1] = next;
        if (!run_foo(value - next, sum_parts, max_count, count + 1))
            return 0;
    }

    // Print result
    if (sum_parts[count] < value) {
        for (int i = 1; i <= count; i++) {
            printf("%d + ", sum_parts[i]);
        }
        printf("%d\n", value);
    }
    return 1;
}

int foo(int value, int sum_parts[], int max_count)
{
    if (max_count < 1)
        return 0;
    sum_parts[0] = 0;
    return run_foo(value, sum_parts, max_count, 0);
}

int main()
{
    const int max_count = 10;
    int sum_parts[max_count];
    foo(15, sum_parts, max_count);
}


输出量:
在这里,一个数组被用来存储当前值的路径,递归调用试图通过只使用比上次使用的值大的值来从剩余的值中构建一个值。这会使用更多的内存,但性能应该会更好。
请注意,由于数组本质上是一个堆栈,因此您可能完全不需要递归就可以实现此解决方案,只需额外注意一点。这是一个完美的 “读者练习”

相关问题