排列組合中的搜索

本質是都是樹的深搜,只不過是遞歸的出口條件,輸出形式以及遞歸過程的條件不一樣。

1:全排列問題:

輸入:3

           1 2 4       

 輸出:

1 2 4

1 4 2

2 1 4

2 4 1

4 1 2

4 2 1

參考代碼實現:

#include<iostream>
#include<stdio.h>
using namespace std;
#define  maxn 15
int n;
int num[maxn];//輸入n個數
int used[maxn];//標記num[i]是否使用過
int rcd[maxn];//標記每個位置的數
void  fullSort(int k)//全排列函數
{
   if(k==n)
   {
     for(int i=0;i<n;i++)
     {
       printf("%d",rcd[i]);
       if(i<n-1)printf(" ");
     }
     printf("\n");
     return;
   }
   else
    {
      for(int j=0;j<n;j++)//枚舉所有的數
      {
         if(!used[j])//若num[i]沒有使用過,則標記爲已用
         {
            used[j]=1;
            rcd[k]=num[j];//在k的位置上放上該數
            fullSort(k+1);//填寫寫一個位置
            used[j]=0;//回溯,清零標記
         }

      }

    }

}
int  read_data()
{
    int i;
    if(scanf("%d",&n)==EOF) return 0;
    for(i=0;i<n;i++)scanf("%d",&num[i]);
    for(i=0;i<n;i++) used[i]=0;
    return 1;
}
int main()
{
    while(read_data())fullSort(0);//從第一位置開始
    return 0;
}


2:一般組合問題:

輸入:4 3

         1 2  3 4

輸出:1 2 3

           1 2 4

           1 3 4

           2 3 4

參考代碼實現:

/*選擇組合排列 C(4,3)*/
#include<iostream>
#include<fstream>
using namespace std;
#define maxn 15
int n,m;
int rcd[maxn];
int num[maxn];
void  select_Combination(int k,int p)
{
    if(k==m)
    {
       for(int i=0;i<m;i++)//只要填滿m個位置就要輸出
       {
         printf("%d",rcd[i]);
         if(i<m-1) printf(" ");
       }
        printf("\n");
        return;
    }
    else
    {
      for(int j=p;j<n;j++)//無序,上一次位置是num[p-1],所以這一次位置從num[p],試探填充。不需要標記有沒有用過。
      {

         rcd[k]=num[j];
         select_Combination(k+1,j+1);//填下一個位置。
      }

    }

}
int  read_data()
{
    if(scanf("%d%d",&n,&m)==EOF) return 0;
    for(int i=0;i<n;i++)scanf("%d",&num[i]);
    return 1;
}
int main()
{
    while(read_data())select_Combination(0,0);
    return 0;
}

3:n個數的集合問題(2的n次方-1個情況)

輸入: 3

          1 2 3

輸出:1

          1 2

          1 2 3

          1 3

          2

          2 3

          3

參考代碼實現:

 

/*求n個數所有集合 */
#include<iostream>
#include<stdio.h>
#include<time.h>
using namespace std;
#define maxn 15
int n;
int rcd[maxn];
int num[maxn];
void full_Combination(int k,int p)
{
   int i;
   for(i=0;i<k;i++)//每次進入遞歸函數都輸出。
   {
     printf("%d",rcd[i]);
     if(i<k-1) printf(" ");
   }
   if(k)printf("\n");
   for(i=p;i<n;i++)//循環從p開始,結束條件i>=n;
   {
      rcd[k]=num[i];//填寫該位置的數。
      full_Combination(k+1,i+1);//下個位置
    }
}
int  read_data()
{
    if(scanf("%d",&n)==EOF) return 0;
    for(int i=0;i<n;i++)scanf("%d",&num[i]);
    return 1;
}
int main()
{
    //int start,end;
    //start=clock();
    while(read_data())full_Combination(0,0);
    //end=clock();
    //cout<<(double)(end-start)/CLOCKS_PER_SEC<<endl;
    return 0;
}

4:不重複排列

輸入:3

          1 1 2

 輸出:1 1 2

            1 2 1

            2 1 1

思路:如果像第一種那樣,就會多出1 1 2 ,2  1 1,1 2 1的重複,思想是記錄本質不同的數出現的次數,輸入的過程要過濾重複的元素。把循環的長度減少到不同元素的個數。

參考代碼實現:

#include<iostream>
#include<stdio.h>
using namespace std;
#define maxn 10
int n,m;
int rcd[maxn];
int used[maxn];
int num[maxn];
void norepeat_Sort(int k)
{
    if(k==n)
    {
       for(int i=0;i<n;i++)
       {
          printf("%d",rcd[i]);
          if(i<n-1)printf(" ");

       }
     printf("\n");
     return;
    }
    else
    {
      for(int j=0;j<m;j++)//枚舉不同元素的個數
      {
       if(used[j]>0)//若num[i]還沒用完,繼續用這個數填充下個位置。
       {
        used[j]--;//可用次數減少
        rcd[k]=num[j];
        norepeat_Sort(k+1);//填寫下個位置
        used[j]++;//可用次數還原
       }
      }
    }
}
int read_data()
{
    int i,j,val;
    if(scanf("%d",&n)==EOF)return 0;
    m=0;
    for(i=0;i<n;i++)
    {
        scanf("%d",&val);
        for(j=0;j<m;j++)//刪選不同的元素,並記錄每一元素記錄的次數。
        {
          if(num[j]==val)
          {
            used[j]++;
            break;
          }
        }
        if(j==m)
        {
         num[m]=val;
         used[m++]=1;
        }
    }
 return 1;
}
int main()
{
    while(read_data())norepeat_Sort(0);
    return 0;
}

5:不重複的組合

輸入:3

         1 1 3

輸出:1

          1 1

          1 1 3

          1 3

          3

思路:同上(本質一樣)

參考代碼實現:

#include<iostream>
#include<stdio.h>
using namespace std;
#define maxn 10
int n,m;
int rcd[maxn];
int used[maxn];
int num[maxn];
void norepeat_Comb(int k,int p)
{
    for(int i=0;i<k;i++)//每次都輸出
       {
          printf("%d",rcd[i]);
          if(i<k-1)printf(" ");

       }
     if(k)printf("\n");
     for(int j=p;j<m;j++)//從P開始,枚舉不同元素的個數
      {
       if(used[j]>0)//若num[i]還沒用完,繼續用這個數填充下個位置。
       {
        used[j]--;//可用次數減少
        rcd[k]=num[j];
        norepeat_Comb(k+1,j);//這裏從j開始,不是j+1;因爲不止一個數、
        used[j]++;//可用次數還原
       }
      }

}
int read_data()
{
    int i,j,val;
    if(scanf("%d",&n)==EOF)return 0;
    m=0;
    for(i=0;i<n;i++)
    {
        scanf("%d",&val);
        for(j=0;j<m;j++)//刪選不同的元素,並記錄每一元素記錄的次數。
        {
          if(num[j]==val)
          {
            used[j]++;
            break;
          }
        }
        if(j==m)
        {
         num[m]=val;
         used[m++]=1;
        }
    }
 return 1;
}
int main()
{
    while(read_data())norepeat_Comb(0,0);
    return 0;
}


 

 


 

           

 

 

 

發佈了32 篇原創文章 · 獲贊 5 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章