組合的輸出(回溯、dfs)


問題 O: 【回溯法】組合的輸出

題目描述

排列與組合是常用的數學方法,其中組合就是從n個元素中抽出r個元素(不分順序且r<=n),我們可以簡單地將n個元素理解為自然數1,2,…,n,從中任取r個數。

現要求你不用遞歸的方法輸出所有組合。

例如n=5,r=3,所有組合為:
    l 2 3    l 2 4    1 2 5    l 3 4    l 3 5    1 4 5    2 3 4    2 3 5    2 4 5    3 4 5

輸入

一行兩個自然數n、r(1<n<21,1<=r<=n)。

輸出

所有的組合,每一個組合占一行且其中的元素按由小到大的順序排列,每個元素占三個字符的位置,所有的組合也按字典順序。

樣例輸入

5 3

樣例輸出

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

這個題是典型的回溯,讓我對回溯的清空狀態有了一定的理解,寫成了dfs。
代碼如下:

 1 #include <bits/stdc++.h>
 2 int n,r,a[25];
 3 bool vis[25];// 來記錄各個數字是否被訪問
 4 using namespace std;
 5 void dfs (int dep)//dep代表搜索的深度,即當前數組a添加了多少個數
 6 {
 7     for (int i=a[dep-1]+1;i<=n;++i)//從上一個添加的數+1開始搜索數字
 8     {
 9         if (!vis[i])//如果這個數字沒被訪問過
10         {
11             a[dep]=i;//將這個數字添加到a里面去
12             if (dep==r)//如果添加的數字達到r個,把他們輸出
13             {
14                 for (int j=1;j<=r;++j)
15                 printf("%3d",a[j]);
16                 printf("\n");
17             }
18             else
19             dfs(dep+1);//如果達不到r個繼續添加
20             vis[i]=0;//回溯,清空當前狀態,把vis[i]設為沒有訪問過。
21         }
22     }
23 }
24 int main()
25 {
26     while (~scanf("%d%d",&n,&r))
27     {
28         memset(a,0,sizeof a);
29         memset(vis,false,sizeof vis);
30         dfs(1);//寫成dfs很巧妙
31     }
32     return 0;
33 }
34 /*
35     Time:12 ms
36     Memory:1696 kb
37 */

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM