重写--全排列--全面理解搜索
问题一:题意:输入一个整数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 }