DFS与排列组合(C语言描述)#1

用DFS求组合

先看题目:
排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。

现要求你输出所有组合。

例如n=5,r=3n=5,r=3,所有组合为:
123,124,125,134,135,145,234,235,245,345;
再上题解:无回溯递归DFS

#include<stdio.h>
int n=0,r=0;
int a[25],b[20000];
int i=0,j=0,k=0,t=0,t1=0,t2=0;
void dfs(int i,int k)
{
    
    
if(i==n+1)
return;
i++;
//printf("i:%d t:%d k:%d\n",i,t,k);//用于检验
if(k==r)//位数达到时输出且返回上层
{
    
    for(j=0;j<r;j++)
{
    
    printf("%3d",a[j]);}
printf("\n");
return;
}
a[k]=i;//存入数组
dfs(i,k+1);//选入,此处i不必加入参数
dfs(i,k);//不选

}
int main()
{
    
    
scanf("%d %d",&n,&r);
dfs(0,0);
return 0;
}

原理:
n<21给了很大的操作空间
用DFS递归,每个数都有两个选择:选入组合or不选入;
在这里插入图片描述
这种方法的好处就是不存在回溯问题,缺点是耗时大,由图可知,这种方法其实给出了x位数不同组合的可能,哪怕一个都不选最后都包括在内。从第一位开始没一位都有两种可能,不考虑位数限制时间复杂度应为2^n,在n<21时可以放心使用(且不用担心顺序问题)。
举一个反例
在这里插入图片描述
从某种角度来说这题依然是可以用组合的方法解决(n个数求其为2的组合)

int abss(long long g,long long h)
{
    
    if(g>=h)
return g-h;
    else
        return h-g;
}
void dfs(long long i,long long k)
{
    
    if(i>n)
        return;
    i++;
    //printf("i:%lld k:%lld\n",i,k);
    if(k==2)
    {
    
    
        j=abss(b[1],b[0]);
        //printf("%lld %lld\n",b[0],b[1]);
        if(j==c)
            sum++;

        return;
    }
    b[k]=a[i];
    dfs(i,k+1);
    dfs(i,k);
}

修改条件后打版提交在三个test中TL
所以说,这种方法在数据量大时容易直接暴毙
包括背包问题,若是我们能列举所有组合可能,自然问题迎刃而解,但由于时间限制不允许很多时候只能DP,或者用带回溯DFS
排列问题也是同理,需要带回溯DFS
(两道例题来自洛谷。)

猜你喜欢

转载自blog.csdn.net/weixin_43736127/article/details/105563197