【问题标题】:Generating increasing subsequences out of n numbers of length k从长度为 k 的 n 个数中生成递增的子序列
【发布时间】:2018-04-17 15:10:00
【问题描述】:

我想生成从 1 到 n 的所有可能增加的数字子序列(允许重复),但长度为 k。
前任。 n=3, k=2
输出:

1 1
1 2
1 3
2 2
2 3
3 3

这是我的代码:

#include <stdio.h>

int s[100];
int n=6;
int k=4;

void subk(int prev,int index)
{
    int i;
    if (index==k)
    {
        for(int i=0; i<k; i++)
            printf("%d ",s[i]);

        printf("\n");
        return;
    }
    s[index]=prev;
    for (i=prev; i<=n; ++i)
    {
        subk(i,index+1);//,s,n,k);
    }

}
int main()
{
    int j;
    for (j = 1; j<=n ; ++j)
    {
        subk(j,0);
    }
    return 0;
}    

但这会产生一些不必要的重复。如何消除这些?

【问题讨论】:

  • 为什么在if条件下使用return语句??
  • int s[100]; 全局声明,然后在 main() 中声明 int s[4];。为什么?
  • @Vijayraj S ( 1, 1 ), ( 2, 2 ) 和 ( 3, 3 ) 不是递增子序列。
  • @VladfromMoscow,但我也需要这些子序列
  • @AditiRawat 抱歉。谢谢指出

标签: c arrays loops recursion subsequence


【解决方案1】:

我已经用n = 3k = 2 测试了你的代码,得到了以下结果:

1 1
1 1
1 1
1 2
1 2
1 3
2 2
2 2
2 3
3 3

这显然是不正确的,因为有几个相同的数字,例如 1 11 2

但究竟出了什么问题?
如果n = 3k = 3,让我们写下正确的结果。现在将它们与我们在n = 3k = 2 时从程序中得到的结果进行比较。

    correct      program (incorrect)
    k = 3        k = 2
    1 1 1        1 1     
    1 1 2        1 1     
    1 1 3        1 1     
    1 2 2        1 2     
    1 2 3        1 2     
    1 3 3        1 3     
    2 2 2        2 2     
    2 2 3        2 2     
    2 3 3        2 3     
    3 3 3        3 3     

现在我们可以看到,当我们设置k = 3时,程序的错误输出与正确答案的前两列相同。这意味着如果我们设置k = 2,程序解决了3列的问题,但只显示前两列。

您需要阻止程序多次写入相同的数字。

解决方案 1

一种方法是在 subk 函数中只执行一次 for 循环,当它将最后一个数字 (index == (k - 1)) 写入缓冲区 s 时。 为了实现这一点,您需要在 for 循环的末尾添加以下两行。

if (index == (k - 1))
    break;

(你也可以使用 return 代替 break

添加这两行后,函数应如下所示:

void subk(int prev, int index)
{
    int i;
    if (index == k)
    {
        for (int i = 0; i<k; i++)
            printf("%d ", s[i]);

        printf("\n");
        return;
    }
    s[index] = prev;
    for (i = prev; i <= n; ++i)
    {
        subk(i, index + 1);//,s,n,k);
        if (index + 1 == k)
            break;
    }

}

解决方案 2

解决问题的另一种方法是将行s[index] = prev;移动到函数的开头,并将if语句中的k更改为k - 1
现在函数应该是这样的:

void subk(int prev, int index)
{
    int i;
    s[index] = prev;

    if (index == k - 1)
    {
        for (int i = 0; i<k; i++)
            printf("%d ", s[i]);

        printf("\n");
        return;
    }

    for (i = prev; i <= n; ++i)
    {
        subk(i, index + 1);//,s,n,k);
    }
}

使用此解决方案,当index 显示程序位于最后一个“子编号”时,永远不会执行 for 循环。它只是显示数字并因为返回而退出函数。

这两种解决方案都得到了正确的结果,但我个人更喜欢第二种解决方案,因为没有额外的 if 语句在 for 循环的每次迭代中执行,而且程序(稍微)更快。

【讨论】:

    猜你喜欢
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多