例题:HDOJ1342
题目大意:
输出从给定的k个数中选取6个数的所有选取方法
题解:
dfs的入门题型是全排列题,其实和这类题很像
全排列题目中dfs函数的写法:
void dfs(int step){
if(step==Volume+1){
输出标记数组
}
for(int i=0;i<Volume;i++){
if(vis[a[i]]==0{
b.push_back(a[i]);
vis[a[i]]=1;
dfs(step+1);
b.pop_back();
vis[a[i]]=0;
}
}
}
我们从这个代码入手,分析选取问题的写法
这个dfs函数中的for循环中每个位置的元素序号都是从0开始的,也就是说很可能出现后面的元素序号比前面的元素的序号小的问题。这样会导致重复的选取出现。
比如:1 2 3 4 和1 2 4 3
要使得选取问题中不出现重复,最好使得后面的元素序号大于前面的,这样是不可能出现重复的情况。
这样我们在代码上加上一个参数NowMax来记录当前选取过的最大序号以使得下一个位置的序号从NowMax+1开始
选取问题的dfs:
void dfs(int step ,int NowMax){
if(step==Volume+1){
输出标记数组
}
for(int i=NowMax+1;i<Volume;i++){
if(vis[a[i]]==0{
b.push_back(a[i]);
vis[a[i]]=1;
dfs(step+1,i);
b.pop_back();
vis[a[i]]=0;
}
}
}
不过这样写记得主函数中要dfs(1,-1),因为最初还没有选取元素
这样,我们就使得每一个输出的序列都是递增的,这样如果不是完全相同的序列,那么就不可能是重复的。
其实这个代码中的vis数组是可以省略的,因为每个for循环都是从前面所有序号中最大的序号后开始遍历的,所以前面也就不可能出现过要遍历的数
选取问题最终版本dfs:
void dfs(int step ,int NowMax){
if(step==Volume+1){
输出标记数组
}
for(int i=NowMax+1;i<Volume;i++){
b.push_back(a[i]);
dfs(step+1,i);
}
}