DFSと順列と組み合わせ(C言語での説明)#2

タイトルの説明:
1からnまでの自然数のすべての非反復順列、つまりnの完全な順列を出力します。生成された数列に反復数が表示されないようにする必要があります。
サンプル入力:
3
サンプル出力:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
最初のアップロードコード:
バックトラッキングDFSを使用したC言語の説明

#include<stdio.h>
int n=0;
int k=0,l=0,m=0;
int a[100];
int b[100];
void dfs(int k)
{
    
    int i=0;
    if(k==n){
    
    
        for(i=0;i<n;i++)
        printf("%5d",a[i]);
        printf("\n");
        return;
    }
        for(i=1;i<=n;i++)
        if(b[i]==0)//这个数没用过
        {
    
    
        a[k]=i;//纳入数组
         b[i]=1;//标记使用
        dfs(k+1);//往下填
        b[i]=0;//回溯
        }
}
int main()
{
    
    scanf("%d",&n);
dfs(0);
    return 0;
}

ここで2つの点に注意してください
。1.dfs(k + 1)はk ++、++ kではあり
ません。2.iはグローバルを開かないでください値は再帰で洗い流されます。
原則:
ここに画像の説明を挿入します
図に示すように、プルーニングに使用された要素に遭遇した場合、例として[123]の1から始めて、1に
ループし、再帰検索123を入力し、12 13を保持します(11を除く)。検索を続行し、123 132を除外します(121、122、131、133)。
上記は配置です。
補足:ナップサック問題には、再帰的DFSのバックトラックが使用されます。
制限時間は、DFSがナップサック問題に使用できるかどうかを決定します。答えを追求することからは実行可能ですが、時間の観点からACすることは困難です。
一次元バックパック:

#include<stdio.h>
int n=0,m=0,x=0;
int a[103][3],b[15000];
int i=0,j=0,k=0,sum=0,l=0,p=0,y=0;
int c[101];
int max(int a,int b)
{
    
    
    if(a>=b)
        return a;
    else
        return b;
}
void dfs(int sum,int k,int i)
{
    
    
int z=0;
        int j=0;
for(j=i;j<=n;++j){
    
    
    if(c[j]==0)
              if(a[j][1]<=k)
        {
    
    z=1;
        c[j]=1;
        dfs(sum+a[j][0],k-a[j][1],i+1);
        c[j]=0;
        }
}
if(z==0)
    {
    
    y=max(y,sum);
    return;}
}
int main()
{
    
    int max=0;
scanf("%d %d",&m,&n);//m为重量限制,n为可选择数目
for(i=1;i<=n;i++)
{
    
    
    scanf("%d %d",&a[i][1],&a[i][0]);
}
dfs(0,m,1);
printf("%d",y);
return 0;
}

二次元バックパック:

#include<stdio.h>
int n=0,m=0,x=0;
int a[103][3],b[15000];
int i=0,j=0,k=0,sum=0,l=0,p=0,y=0;
int c[101];
int max(int a,int b)
{
    
    
    if(a>=b)
        return a;
    else
        return b;
}
void dfs(int sum,int k,int l,int i)
{
    
    
int z=0;
        int j=0;

for(j=i;j<=n;++j){
    
    
    if(c[j]==0)
              if(a[j][1]<=k&&a[j][2]<=l)
        {
    
    z=1;
        c[j]=1;
        dfs(sum+a[j][0],k-a[j][1],l-a[j][2],i+1);
        c[j]=0;
        }
}
if(z==0)
    {
    
    y=max(y,sum);
    return;}
}
int main()
{
    
    int max=0;
scanf("%d %d %d",&n,&m,&x);//n为可选择数目,m为数据限制1,x为数据限制2
for(i=1;i<=n;i++)
{
    
    
    scanf("%d %d %d",&a[i][0],&a[i][1],&a[i][2]);
}
dfs(0,m,x,1);
printf("%d",y);
return 0;
}

両方のコードは円でテストされており、データが十分に大きい場合はTLになりますが、結果自体は問題ありません。
前の記事の選択または選択ツリーは、スキーの問題にも使用できます。dfs(i + 1、j-1)dfs(i + 1、j + 1)を再帰的
に取得するのと同様ですが、ここでも時間制限があります。非常に多くの人がDFSになる可能性があります問題は最終的にはDPにしかなり得ません。まさか、一次元のバックパックを取り付けてください。回答:



#include<stdio.h>
int dp[101][1005];
int max(int a,int b)
{
    
    
    if(a>=b)
        return a;
    else
        return b;
}
int main()
{
    
    int n=0,k=0,i=0,j=0,m=0;
int a[103],b[103];
scanf("%d %d",&n,&m);
for(i=1;i<=m;i++)
    scanf("%d%d",&a[i],&b[i]);
for(i=1;i<=m;i++)
   for(j=n;j>=0;j--)
   {
    
    
       if(a[i]<=j)
        dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]]+b[i]);
        else
        dp[i][j]=dp[i-1][j];
   }
   printf("%d",dp[m][n]);
    return 0;
}

概要:DPはDPです。DFSがそれを実行できる場合でも、コードや時間の複雑さに関係なく、DPの見た目は良くなります。
元々は順列と組み合わせでしたが、

原子の数は無制限で、形も多様です。
すべてが整理され、組み合わされます。
————デモクリトス

おすすめ

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