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再帰では、各数値には2つの選択肢があります。組み合わせを選択するかどうか。
ここに画像の説明を挿入します
この方法の利点は、バックトラックの問題がないことです。欠点は、時間であるということです。図からわかるように、この方法では、実際にはx桁のさまざまな組み合わせが可能であり、1つが選択されていなくても、最後に含まれます。最初の桁から始めて、桁がない場合は2つの可能性があります。桁数に関係なく、時間計算量は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);
}

条件を変更した後、3つのテストでバージョンがTLに送信される
ため、この方法は
、バックパックの問題を含め、データ量が多い場合に直接強制終了するのが簡単です。考えられるすべての組み合わせをリストできれば、自然な問題です。解決されますが、時間の制約のため、多くは許可されません。DPのみ、またはバックトラッキングでDFSを使用できます
配置の問題は同じであり、DFSをバックトラックする必要があります
(2つのサンプル質問はLuoguからのものです。)

おすすめ

転載: blog.csdn.net/weixin_43736127/article/details/105563197