排列数
解空间大小为2^n,选与不选
void dfs(int x){
if(x == n+1){//所有数全部排列完成
//output
return;
}
for(int i = 0 ;i < n; i++){
if(vis[i] == 0){//没有遍历过
vis[i] = 1;
a[x] = i;//存储该数
dfs(x+1); //位置加1
vis[i] = 0;//回溯
}
}
//可以使用vector存储
/*for(int i = 1 ; i <= n ;i++){
if(!vis[i]){
vis[i] = 1;
p.push_back(i);
dfs(x+1);
vis[i] = 0 ;
p.pop_back();//一定要弹出哦
}
}
*/
}
dfs(x+1);//注意这个地方只是位置增加,但是for循环里面i还是从1开始,还是一个一个看有没有访问过,没访问的往里面加元素,
组合数问题/排列数
问题规模n!,两两组合
void dfs(int start,int res){
if(组成数的个数达到要求){//
//output
return;
}
for(int i = start ; i <= n ;i++){
if(!vis[i]){
vis[i] = 1;
p.push_back(i);
dfs(start+1,res+1);
}
}
}
此时for 循环从i = start 开始,且start +1 ,保证不重复
实例
选数问题
给定若干个正整数a0、a0 、…、an-1 ,从中选出若干数,使它们的和恰好为k,
要求找选择元素个数最少的解。如果有多个最优解,输出字典序最小的。
输入格式:
输入有两行,第一行给出2个正整数n,k,用空格分隔。第二行是用空格分隔的n个整数。
输出格式:
输出有两行,第一行从小到大输出选择的元素,第二行输出元素的个数。
输入样例:
在这里给出一组输入。例如:
5 9 1 1 4 5 7
输出样例:
在这里给出相应的输出。例如:
4 5 2
注意该问题的限制条件
子集和 字典序列最小(包含的数个数最少的)
//组合数从第二个开始选择
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int a[10000];
int n,k;
int vis[1000];
vector<int> p;
vector<int> c;
int minn = 100;//定义最少元素个数
void dfs(int start,int sum,int size){
if(sum == k){
if(minn>size){
minn = size;//记录最小元素元素个数
c.clear();
for(int i = 0 ;i<size;i++)
c.push_back(p[i]);
}
}
if(start >= n) return ;
if(sum > k) return ;
for(int i = start ;i < n;i++){
if(!vis[a[i]]){
vis[a[i]] = 1;
p.push_back(a[i]);
dfs(start+1,sum+a[i],size+1);//组合问题
vis[a[i]] = 0;
p.pop_back();
}
}
}
int main(){
cin>>n>>k;
for(int i = 0 ;i < n;i++)
cin>>a[i];
sort(a,a+n);
dfs(0,0,0);
for(int i = 0; i < c.size();i++){
cout<<c[i];
if(i!=c.size()-1){
cout<<" ";
}
else cout<<endl;
}
cout<<c.size();
return 0;
}