ホワイト学校アルゴリズム:DFSの順列と組み合わせの問題

準備:

用語と問題のいくつかを説明し、理解を容易にします。
、との配列の先頭から1つのインデックスは、インデックス0ません。
2.dfsはゼロ深さ1、再帰的に呼び出されると深さ2、及び上のいわゆる再帰します。
3.それぞれの深さは、集合的に、いくつかの操作を実行する演算処理の深い空間をDFS。
図1の構成4.トラバース組み合わせ解法を説明します

アレンジメント

問題:を含むテーブルn個の要素の数、から選択された数kが与えられると、多くの順列を構成することができる
出力および順列の総数は、各オペランドの三の広視野の各順列を。
コードの場合:

#include <iostream>
#include <cstdio>
using namespace std;
int number[100];  //存储数表 
int book[100];  //哨兵 ,初始为0,代表未使用过 
int num[100];  //存储找到的排列 
int n,k,count;  //n为数表的长度,k为每个排列数包含的元素个数,count为总的排列数

void dfs(int step){
 if( step == k+1){    //step从 1 开始计算,当step == k+1 时,表示找到了一种排列 
  for(int i = 1;i<=k;i++)
   printf("%3d",num[i]); //输出排列数 
  printf("\n");
  count++;  //排列数个数 +1 
  return ;
 }
 for(int i = 1;i<=n;i++){
  if(book[i]==0){
   book[i]=1;   //标记点A, 1 表示该元素已用 
   num[step]=number[i];//将当前元素放在存储排列数的数组中 
   dfs(step+1);        //进入下一个深度空间 
   book[i]=0;   //标记点B,回溯时,将当前点标记为未用 
  }
 }
 
 return;
}

int main()
{
 scanf("%d %d",&n,&k);
 
 for(int i=1;i<=n;i++)  //注意,数组从 1 号索引开始使用 
  scanf("%d",&number[i]);
 printf("\n");
 dfs(1);         //进入dfs,当前:深度为1,递归0次 
 printf("%3d",count);
 return 0;
}

組み合わせ

組成問題:
数kを選択したn個の要素を含むテーブルの数を考えると、構成することができる組み合わせの数
、各組合せの出力との組み合わせの総数を、広いフィールド番号3の各
コードに:

#include <iostream>
#include <cstdio>
using namespace std;
int number[100]; //存放数表 
int num[100];  //存放查找到的组合数 
int count,n,k;   //count记录总的组合数个数,n为数表长度,k为每个组合数包含元素的个数

void dfs(int step,int startx) //step为深度,startx表示当前深度循环开始的索引 
{
 if(step == k+1){  //step从 1 开始计算,当step == k+1 时,表示找到了一种组合
  for(int i=1;i<=k;i++){
   cout << "   " << num[i];//输出找到的组合数 
  }
  cout << endl;
  count++;  //组合数个数 +1 
  return ;
 }
 for(int i=startx;i<=n;i++){
  num[step]=number[i];//将当前元素放在存储组合数的数组中 
  dfs(step+1,i+1); // i+1 表示下一深度的循环只能遍历当前索引之后的数(此处记为标记点C) 
 }
}

int main()
{
 cin >> n >> k;
 for(int i=1;i<=n;i++) //注意,数组从 1 号索引开始使用 
  cin >> number[i];
 dfs(1,1);  //进入dfs,当前:深度为1,递归0次,循环从第一个元素开始遍历 
 cout << "   " << count;
}

分析

分析の焦点は、さまざまな理由のこれら2つのコードということです。その理由を探ることに深い循環とセンチネルの役割を理解します。
:ここで、これら2つのコードの間の差参照することは容易であり
、異なる出発点1サイクル。
2.見張りの使用は、使用されていません。
のは、さまざまな理由を描画することによって、それらを見てみましょう。
質問紹介:私たちは、地図上の考えでは、問題の組み合わせを手配します。以下は、
ここに画像を挿入説明

一つの問題は、分析アレンジメント

質問:三つの要素の図では、任意の二つの要素が配列を構成する選択し、どのように多くのオプションプログラムの合計?
解決策:
最初のステップ:私たちをから1 歩行を開始し、我々が得ることができます 12132つの構成。
ステップ2:いつから2配置の原則に従って、私が持っていることができ、時間がかかるようになりました213スキーム2つの構成。
質問があるので、(問題のXとして記録):
私は2から行くようになったとき、どのように私は2の深さでの操作空間を確保するか、私はの横断されている要素(つまり、ここでは2である)以外のすべての要素をトラバースすることができますか?

サイクリングデビュー

私は、反復処理するループを設定します1〜n個要素、そしてIあなたは運転中に各深さでのスペースを横切ることができるすべての要素をここにある全ての要素が、これがある(もちろん、すでに横断要素の含め、2)。それでは、どの除く要素を横断しますか?

グレートデビューセンチネル

私たちは、各要素を通過すると、要素は次のようにマークされて置くすでに使用し、次の深宇宙、センチネルの報告、我々は要素が横断されている再反復を避けることができます。これは、役割マークポイントAです。したがって、Xの問題はまだ解決されていませんか?
だから、問題がある:マークポイントBは何をしているのですか?なぜあなたが時間内に戻って行きたいと現在の要素としてマークされます未使用これ?
探求し続け、我々は栗を与える:
ここに画像を挿入説明
何も存在しない場合、マーカーBは
ときに我々1見つけるために、開始点として、1213後、その後1つの操作空間の深さ、およびへのバックは大きな問題は、Sentinelは報告されている:「我々は、の使用可能な要素を持っていません!」
これは明らかに、ああ、点Bの役割をマークするために、この時間が明らかにされるではありません。
私たちは見ているマーカーBの状況:
検索を1213後、我々は深さに戻りました1以来、計算空間、この時、Bはマーカ点が存在し、1,2及び要素が未使用とマークされます報告SENTINELあなたが言います: "2ノー要素利用可能!「そして、私たちのことができるようになります2開始点として、新たに配置スキームを見つけるために続けています。

次の要約での巡回置換の問題の下センチネル、

フルサイクル各オペレータの宇宙空間の深さのすべての要素を通過できることを保証するためにすべての要素をトラバースを指します。
衛兵:マーカーがAを指し、現在の要素が使用されているとするとき、単一のルックアップ、整列していないことを確実にするために配置され、
マーカ点B要素の配置が判明しているを使用する場合、保証別の順列方式を探しているときに使用することができます。

ここではそれは我々が説明し、別の栗を与え、少し複雑です。

マーク点A:いつから1[スタート]、スペース2の深さに再帰的な操作、私は、もはや使用することができます1要素の数。12(または、13)です現在の配置1現在の配列のどの要素が既に使用される要素ではありません。
**マーカーB:**私は見つけます1213時間(この時間1213私はまだすることができ、)配置の2が既に使用される要素を探して、発見された配置があります2開始点として、再び新しい配置プログラムを見つけることができます。

第二の問題:分析の組み合わせ

我々が言う前に。組合せおよび順列コードブロックの循環やセンチネルの違いを使用しての面で、
比較の配置、我々は組み合わせが使用されていないことを発見した歩哨を、およびない完全なサイクルをもちろん、使用されるループコードの組み合わせは、彼の開始点は、現在のDFSの深さがある(私たちは、このサイクルを呼びましょう開始サイクルを変更します)。

私たちの組み合わせはなぜ見張り、そして使用して探索するために使用されていないと可変サイクル開始点を

(まだ使用中の上図)栗を移動するための時間に行ってきました:
ここに画像を挿入説明
私たちが使用している場合はセンチネル+フルループを組み合わせて:
ときに私たちから2スタート横断,,その後、我々が得ます2123、(から1トラバースするときにはでした12)そして、2112どうやら組み合わせを繰り返しました。

問題のこの組み合わせことを繰り返さないようにする方法?

私たちは、なぜそこに最初の探検します21この組み合わせは繰り返されます。もちろん、我々はので、開始点を通過します2要素の前に1、要素は、開始点の前に我々はトラバース、まだ表示されない組み合わせを繰り返さないようにしていない場合は?どのようにそれを行うには?

これは、循環デビューの開始点となります

サイクルの開始時点を変化させることにより、その要素は前の出発点トラバースないことを確実にするために簡単です。

コードの下の組み合わせがセンチネルを使用していない理由の探求してみましょう

ので、唯一の開始点・サイクルは、ポイント番号を開始するいくつかのテーブルを通過した後、残りの変更マーカAマーカBの問題は自然にあなたが歩哨を必要としない、表示されませんここで扱わ。(中略)。

ホワイトは、生産ギャング翼を歓迎します

ここに画像を挿入説明

リリース元の2件の記事 ウォンの賞賛0 ビュー31

おすすめ

転載: blog.csdn.net/SX123q/article/details/104793373