c语言入门实例113

给定两个整数 n 和 k。要求选择从 1 到 n 中尽可能多的不重复的整数,以使选择的数字没有任何子集的和等于 k(输出所有满足要求的子集)。我的思路在代码最下方,求各位能顺着我的思路看看我是否有哪些错误且接下来该怎么写


#include<stdio.h>
#include<stdlib.h>
int main() {
    int a, b, g = 0;
    int* arr, numbers1[200], numbers2[200], numbers3[200];
    printf("please input two nummbers.\n");
    scanf_s("%d%d", &a, &b);
    arr = (int*)malloc(a * sizeof(int));
    for (int c = 0;c < a;c++)
    {
        arr[c] = c + 1;
    }
    if (b<=a)
    {
        for (int d = 0;d < a;d++)
        {
            if (arr[d] == b)
            {
                arr[d] = 0;//赋空值让其消失

            }
        }
        for (int e = 0;e < a;e++)
        {
            for (int f = 0;f < a;f++)
            {
                if (b - arr[e] == arr[f])
                {
                    if (arr[e] != 0)
                    {    //length++;
                    //numbers1 = (int*)malloc((length / 2 + a) * sizeof(int));
                    //numbers2 = (int*)malloc((length / 2 + a) * sizeof(int));
                        numbers1[g] = arr[e];
                        numbers2[g] = arr[f];
                        g++;
                    }
                }
                else
                {
                    numbers3[g] = arr[e];
                    g++;
                }

            }
            
        }
        for (int h = 0;h <= g;h++)
        {
            printf("%d", numbers3[h]);
        }
        
    }
    else if (b>a)
    {
        for (int e = 0;e < a;e++)
        {
            for (int f = 0;f < a;f++)
            {
                if (b - arr[e] == arr[f])
                {
                    if (arr[e] != 0)
                    {    //length++;
                    //numbers1 = (int*)malloc((length / 2 + a) * sizeof(int));
                    //numbers2 = (int*)malloc((length / 2 + a) * sizeof(int));
                        numbers1[g] = arr[e];
                        numbers2[g] = arr[f];
                        g++;
                    }
                }
                else
                {
                    numbers3[g] = arr[e];
                    g++;
                }

            }

        }




    }
    free(arr);
    return 0;
}
/*目前未完成,已实现三个部分的分类,还差自由组合输出;思路是 
1.先判断n, k的大小。
2.若n大或等于k则1-n中就会出现k,则含k子集必定存在和为k,所以先将其函数值赋值为0;第二种出现k的形式为相加,即1-n中存在两个数字的和为k,若这两个数字同时存在,同样不能满足子集的和不为k,
所以我的方法是利用减法,即用两个for循环来检验是否存在两个数字的和为k。若存在,则将第一个数字存进numbers1数组,第二个数字存进numbers2数组。若不存在即为单个数字存进numbers3数组。
这样便达到了分类,numbers1与numbers2中同下标的数值不能同时输出,numbers3全输出。但在实现组合的时候有点问题
3.若n小于k则无需考虑1-n中有k,则参照上一种情况的余下方法即可;
2023.813*/

涉及到高中数学的子集,假设n=3 k=2;那我们要从1-3中即1 2 3中尽可能多的选择数字,且需要满足这些数字的任一子集的和不能为k,也就是2;
即答案是 1 3.因为含2的话子集中的2即为k,不满足

以下是一个使用C语言解决该问题的思路:

首先,我们需要定义一个函数来判断给定的数字是否满足条件。假设该函数名为isValid,它接受两个参数:一个整数数组subset,表示当前已选择的数字集合,以及一个整数num,表示要添加到集合中的新数字。

在isValid函数内部,我们需要遍历subset数组,将其中的每个数字与num相加,并检查其是否等于k。如果存在任何一个子集的和等于k,则返回0表示无效,否则返回1表示有效。

接下来,我们可以使用回溯法来生成所有符合条件的数字组合。我们定义一个递归函数,命名为backtrack,它接受四个参数:一个整数数组subset,表示当前已选择的数字集合;一个整数n,表示可选择的数字范围;一个整数k,表示目标和;以及一个整数start,表示开始选择数字的位置。

在backtrack函数内部,首先检查当前的subset数组是否满足条件,即调用isValid函数来判断。如果满足条件,则输出subset数组,并终止递归。

否则,从start位置开始遍历数字,并将其添加到subset数组中。然后调用backtrack函数,将start位置加一递归调用。在递归调用返回后,将当前数字从subset数组中移除,然后继续遍历下一个数字。

在主函数中,我们初始化一个空数组subset,并调用backtrack函数来生成满足条件的数字组合。

下面是一个示例代码:

#include <stdio.h>

int isValid(int subset[], int num, int k) {
    int sum = 0;
    for (int i = 0; i < num; i++) {
        sum += subset[i];
        if (sum == k) {
            return 0;
        }
    }
    return 1;
}

void backtrack(int subset[], int n, int k, int start) {
    if (!isValid(subset, start, k)) {
        return;
    }
    if (start == n) {
        for (int i = 0; i < n; i++) {
            printf("%d ", subset[i]);
        }
        printf("\n");
        return;
    }
    for (int i = 1; i <= n; i++) {
        subset[start] = i;
        backtrack(subset, n, k, start + 1);
        subset[start] = 0;  // 清除当前位置的选择
    }
}

int main() {
    int n, k;
    printf("请输入n和k的值:");
    scanf("%d %d", &n, &k);

    int subset[n];
    backtrack(subset, n, k, 0);

    return 0;
}

这段代码基于回溯法,对于较大的n和k可能会有性能上的限制。

【以下回答由 GPT 生成】

首先,让我们来分析代码中是否存在任何错误或潜在的问题。

  1. 在声明numbers1numbers2numbers3时,使用了固定大小的数组来存储结果。然而,问题未规定结果的最大大小,这可能导致数组溢出或内存浪费。建议改用动态数组或其他动态数据结构来存储结果。

  2. 分配给arr的内存大小应为a * sizeof(int)而不是b * sizeof(int),因为我们想为给定范围内的整数分配内存,而不是为给定的数b分配内存。

  3. 在第一个for循环中,c的初始值是1,而不是0。应将其更正为int c = 0以正确初始化数组arr

  4. b小于等于a时,代码会执行第一个if块,并将指定的数值从arr中删除(将其赋为0)。然后使用两层嵌套循环来查找与指定数值b - arr[e]相等的数字对。

    (a) 在内部循环的条件判断中,应该检查arr[f]是否不为0。如果将0值添加到numbers1numbers2中,可能会导致结果中出现不必要的0。

    (b) 在内部循环的else块中,将arr[e]添加到numbers3中,并且在每次循环迭代时都会增加g的值。这会导致后续循环中的numbers3[g]索引越界,应将其移出循环外来避免此问题。

  5. 在最后一个for循环中,条件应该为h < g而不是h <= g,以正确打印numbers3中的元素。

下面是对以上问题的解决方案:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int a, b, g = 0;
    int* arr;
    int* numbers1;
    int* numbers2;
    int* numbers3;

    printf("please input two numbers.\n");
    scanf_s("%d%d", &a, &b);

    arr = (int*)malloc(a * sizeof(int));
    numbers1 = (int*)malloc(a * a * sizeof(int));
    numbers2 = (int*)malloc(a * a * sizeof(int));
    numbers3 = (int*)malloc(a * sizeof(int));

    for (int c = 0; c < a; c++) {
        arr[c] = c + 1;
    }

    if (b <= a) {
        for (int d = 0; d < a; d++) {
            if (arr[d] == b) {
                arr[d] = 0; // 赋空值让其消失
            }
        }
        for (int e = 0; e < a; e++) {
            for (int f = 0; f < a; f++) {
                if (arr[f] != 0 && b - arr[e] == arr[f]) {
                    numbers1[g] = arr[e];
                    numbers2[g] = arr[f];
                    g++;
                } else if (arr[e] != 0) {
                    numbers3[g] = arr[e];
                    g++;
                }
            }
        }
        for (int h = 0; h < g; h++) {
            printf("%d", numbers3[h]);
        }
    } else if (b > a) {
        // ...
    }

    free(arr);
    free(numbers1);
    free(numbers2);
    free(numbers3);

    return 0;
}

继续编写代码的下一步取决于问题的具体需求和规范。提供的代码片段中没有给出关于"k"的任何说明。如果你能提供更多关于要解决的问题的信息,我可以给出更具体的指导。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^