【问题标题】:Count alternating up / down sequences计数交替向上/向下序列
【发布时间】:2018-03-31 07:18:05
【问题描述】:

问题描述: 计算从某个输入 n 上升的所有序列的数量。 所以用户输入n;用那个 n 然后我创建一个数字数组 1..n 然后用那个属性对序列编号

示例:n = 4

1 3 2 4
1 4 2 3
2 3 1 4
2 4 1 3
3 4 1 2

回答:5

我的程序可以运行,但由于某种原因,我有时会得到 0 而不是答案。

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

void *safeMalloc(int n) {
    void *p = malloc(n);
    if (p == NULL) {
        printf("Error: malloc(%d) failed. Out of memory?\n", n);
        exit(EXIT_FAILURE);
    }
    return p;
}

void swap(int *fir, int *sec) {
    int temp = *fir;
    *fir = *sec;
    *sec = temp;
}

void permute(int *array, int i, int length, int *count) {
    if (length == 2) {
        *count = 1;
        return;
    }
    if (length == i) {
        int v = 0, flag = 1;
        while (v < length) {
            if (v % 2 == 0) {
                if (array[v] < array[v + 1]) {
                    v++;
                } else {
                    flag = 0;
                    return;
                }
            }

            if (v % 2 != 0) {
                if (array[v] > array[v + 1]) {
                    v++;
                } else {
                    flag = 0;
                    return;
                }
            }
        }
        if (flag == 1) {
            /*
            int a;
            for (a = 0; a < length; a++)
                printf("%d", array[a]);
            printf("\n");
            */
            *count = *count + 1;
        }
    }
    int j = i;
    for (j = i; j < length; j++) {
        swap(array + i, array + j);
        permute(array, i + 1, length, count);
        swap(array + i, array + j);
    }
    return;
}

int main(int argc, char **argv) {
    int n;
    scanf("%d", &n);
    int *arr = safeMalloc(n * sizeof(int));
    int i;
    for (i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    int count = 0;
    permute(arr, 0, n, &count);
    printf("%d\n", count);
    return 0;
}

【问题讨论】:

  • which go up down - 请解释一下这是什么意思?
  • 不清楚“从某个输入n 向上向下”是什么意思?这是否意味着类似:一个序列a_1 ... a_k a_{k+1} ... a_n,其中a_1 ... a_k 已排序,然后a_{k+1} ... a_n 再次排序,但a_k &gt; a_{k+1}。排列在哪里发挥作用?此外,使用普通的旧malloc 而不是safeMalloc 是安全的。在大多数设置中,您不太可能会用完内存并且您会比让 malloc 返回 NULL 更早被 OOM 杀死。
  • 看例子:12
  • 请注意,问题需要此类序列的数量,但不要求明确生成这些序列。你有没有想过用数学方法来计算这个数字。也许,某种动态编程/表格填充?

标签: c algorithm recursion


【解决方案1】:

您基本上生成数组元素的所有排列并计算有效的排列。

您的代码有一个小缺陷:

  • 循环while (v &lt; length) { 走得太远了:您访问tab[v + 1],因此循环应该在v &lt; length - 1 处停止。按照目前的编码,它具有未定义的行为。

您可以进一步简单的代码:

  • 应该不需要特殊情况length == 2
  • flag 没用,因为你清除它时总是返回。
  • if (v % 2 != 0) 是多余的:else 就足够了。

这是一个固定的简化版本:

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

void *safeMalloc(int n) {
    void *p = malloc(n);
    if (p == NULL) {
        printf("Error: malloc(%d) failed. Out of memory?\n", n);
        exit(EXIT_FAILURE);
    }
    return p;
}

void swap(int *fir, int *sec) {
    int temp = *fir;
    *fir = *sec;
    *sec = temp;
}

void permutate(int *array, int i, int length, int *count) {
    if (i == length) {
        for (int v = 0; v < length - 1; v++) {
            if (v % 2 == 0) {
                if (array[v] >= array[v + 1]) {
                    return;
                }
            } else {
                if (array[v] <= array[v + 1]) {
                    return;
                }
            }
        }
        *count = *count + 1;
    } else {
        for (int j = i; j < length; j++) {
            swap(array + i, array + j);
            permutate(array, i + 1, length, count);
            swap(array + i, array + j);
        }
    }
}

int main(int argc, char **argv) {
    int n;
    if (scanf("%d", &n) == 1 && n > 0) {
        int *arr = safeMalloc(n * sizeof(int));
        for (int i = 0; i < n; i++) {
            arr[i] = i + 1;
        }
        int count = 0;
        permutate(arr, 0, n, &count);
        printf("%d\n", count);
    }
    return 0;
}

【讨论】:

    【解决方案2】:

    如果您调用 tab(n,k) 长度为 n 的上下序列的数量,其中 k 是序列中的最后一个数字,您可以编写一个递归公式并像这样实现它:

    int N = 5+1;
    int** tab = new int*[N];
    for (int n = 0; n < N; n++) {
        tab[n] = new int[N];
        for (int k = 0; k < N; k++) {
            tab[n][k] = 0;
        }
    }
    tab[1][1] = 1;
    for (int n = 2; n < N; n++) {
        for (int k = 1; k <= n; k++) {
            if (n % 2 == 0) {
                for (int j = 0; j < k; j++) {
                    tab[n][k] += tab[n-1][j];
                }
            }
            else {
                for (int j = k; j < n; j++) {
                    tab[n][k] += tab[n-1][j];
                }
            }
        }
    }
    int res = 0;
    
    for (int j = 0; j < N; j++) {
        res += tab[N - 1][j];
    }
    

    【讨论】:

      【解决方案3】:

      您无需遍历排列即可解决此问题。假设您正在尝试计算 f(n)。新的高数字可以去哪里?它必须处于“向上”位置,这是一个均匀的位置。你可以在它前面有任何奇数长度的有效序列,也可以在它后面有任何有效序列。

      假设我们正在计算 f(n,k),其中最高 val 位于位置 k,索引为零。对于 k 偶数,这为零。对于奇数 k,我们得到:

      f(n,k) = 选择(n-1, k) * f(k) * f(n - k - 1)

      要得到 f(n),将 f(n,k) 与奇数 k

      我们必须手动计算前几个。

      f(0) = 1
      f(1) = 1
      f(2) = 1
      f(3) = f(3,1) = choose(2,1) * f(1) * f(1) = 2 * 1 *1 = 2
      f(4) = f(4,1) + f(4,3) = choose(3,1) * f(1) * f(2) + choose(3,3) * f(3) * f(0) = 3*1*1 + 1*2*1 = 5
      f(5) = f(5,1) + f(5,3) = choose(4,1) * f(1) * f(3) + choose(4,3) * f(3) * f(1) = 4*1*2 + 4*2*1 = 16
      

      【讨论】:

        猜你喜欢
        • 2016-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-22
        相关资源
        最近更新 更多