重写--全排列--全面理解搜索

问题一:题意:输入一个整数n(n <= 9),输出1、2、3、······、n这n个数的全排列(按照字典序输出)。

方法1:暴力写法

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main(){
 5     int n=3, a[20];//以n=3为例,以此类推
 6     for(int i=0; i<n; i++)a[i]=i+1;//初始化序列
 7     
 8     for(int i=0; i<n; i++)
 9         for(int j=0; j<n; j++)
10             if(i!=j)
11                 for(int k=0; k<n; k++)
12                     if(k!=i && k!=j)
13                         //....//当n不等于3时以此类推 
14                         cout<<a[i]<<" "<<a[j]<<" "<<a[k]<<endl; 
15     return 0;
16 }

方法2:搜索写法

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n, m;
 4 int a[100];
 5 bool vis[100];
 6 void dfs(int x)
 7 {
 8     if(x>n){
 9         for(int i=1; i<=n; i++)cout<<a[i]<<" ";
10         cout<<endl;
11         return;
12     }
13     for(int i=1; i<=n; i++)
14     {
15         if(!vis[i])
16         {
17             a[x]=i;
18             vis[i]=1;
19             dfs(x+1);
20             vis[i]=0;
21         }
22     }
23     
24 }
25 int main()
26 {
27     cin>>n;
28     dfs(1);
29     return 0;
30  }

方法3:递归写法

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n, a[10];
 4 
 5 void perm(int begin, int end){
 6     if(begin==end){
 7         for(int i=0; i<=end; i++)
 8             cout<<a[i]<<" ";
 9             cout<<endl;
10     }
11     else{
12         for(int i=begin; i<=end; i++){
13             swap(a[begin],a[i]);//把当前第一个数与后面的所有数交换位置 
14             perm(begin+1,end);
15             swap(a[begin],a[i]);//恢复,用于下次交换 
16         }
17     }
18 }
19 
20 int main(){
21     cin>>n;
22     for(int i=0; i<n; i++)a[i]=i+1;//初始化数组值
23     
24     perm(0,n-1);//perm是permutation简写 
25     return 0;
26 }

方法4:STL输出全排列

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main(){
 5     int n, a[20];
 6     cin>>n;//n小于20 
 7     for(int i=0; i<n; i++)a[i]=i+1;
 8     do{
 9         for(int i=0; i<n; i++)
10             cout<<a[i]<<" ";
11         cout<<endl;
12     }while(next_permutation(a,a+n));//next_permutation注意拼写要牢记 
13     
14     return 0;
15 }

问题二:打印n个数中任意m个数的全排列;

    将问题一中方法2、方法3、方法4更改参数即可

问题三:

从1-m中选出n个数,要求同样的数字不能重复选择,按照字典序正序输出所有方案。

例如:从1到4中选出2个数,共有6种方法,按照字典序输出,依次为:

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

 方法1:更改问题一》方法2》两种更改方法》自行脑补

 方法2:递归写法,理解了你就是大佬

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n, m;
 4 int a[20];
 5 void dfs(int cur, int sel){//cur填数,sel位数 
 6     if(sel==n){
 7         for(int i=0; i<n; i++)
 8             cout<<a[i]<<" ";
 9         cout<<endl;
10         return;
11     }
12     for(int i=cur; i<=m; i++){
13         a[sel]=i;
14         dfs(i+1,sel+1);
15     }
16 }
17 int main()
18 {
19     cin>>m>>n;
20     dfs(1,0);
21     
22     return 0;
23  } 

问题四:打印n个数中任意m个数的组合(子集问题)

 step1:1~n的所有子集(难度较大,从二进制的角度考虑

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[10];
 4 void print_subset(int n)
 5 {
 6     for(int i=0; i<(1<<n); i++){
 7         for(int j=0; j<n; j++)
 8             if(i&(1<<j))
 9                 cout<<a[j]<<" ";
10         cout<<endl;
11     }
12 }
13 int main()
14 {
15     int n;
16     cin>>n;
17     for(int i=0; i<n; i++)a[i]=i+1;//初始化数组 
18     print_subset(n);
19     return 0;
20  } 

 step2:打印1~n个数中任意m个数的组合(和问题二的解法比较)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int a[10];
 4 void print_subset(int n, int m)
 5 {
 6     for(int i=0; i<(1<<n); i++){
 7         int num=0, kk=i;//num统计i中1的个数;kk用来处理i
 8         while(kk){
 9             kk=kk&(kk-1);//清除kk中的最后一个1 
10             num++;//统计1的个数 
11         } 
12         if(num==m){//二进制数中的1有k个,符合条件 
13             for(int j=0; j<n; j++)
14                 if(i&(1<<j))
15                     cout<<a[j]<<" ";
16             cout<<endl;
17         }
18     }
19 }
20 int main()
21 {
22     int n, m;
23     cin>>n>>m;
24     for(int i=0; i<n; i++)a[i]=i+1;//初始化数组 
25     print_subset(n, m);
26     return 0;
27  } 

 

 
posted @ 2019-11-28 09:15  TFLSNOI  阅读(639)  评论(0编辑  收藏  举报