深度优先搜索: 它从某个状态开始,不断地转移状态直到无法转移,然后退回到前一步的状态,如此不断重复知道找最终的解。所以递归函数实现比较容易。
如下例:
部分和问题:
从a1开始按顺序决定每个数加还是不加,在全部n个数都决定后判断它们的和是不是k即可 。
因为状态数是2(n+1),所以复杂度是O2n。
//输入;
int a[max_n];
int n,k;
//已经前i项得到了和sum,然后对于i项之后进行分支
bool dfs(int i,int sum){
//如果前i项都计算过了,则返回sum是否与k相等
if(i==n)return sum==k;
//不加上a[i]的情况
if(dfs(i+1,sum))return true;
//加上a[i]的情况
if(dfs(i+1,sum+a[i]))return true;
//无论是否加上a[i]都不能凑成k就返回false
return false
}
void solve(){
if(dfs(0,0)printf("Yes\n"));
else printf("No\n");
}
深度优先搜索从最开始的状态出发,遍历所有可以到达的状态,由此可以对所有的状态操作,或者列举所有的状态。
例2:
//输入
int n,m;
char field[max_n]][max_n+1]
//现在位置(x,y)
void dfs(int x,int y){
//将现在所有的位置替换为.
field[x][y]='.';
//循环遍历移动的八个方向
for(int dx=-1;dx<=1;dx++){
for(int dy=-1;dy<=1;dy++){
//向x方向移动dx,向y方向移动dy,移动的结果是(nx,ny);
int nx=x+dx,ny=y+ny;
//判断(nx,ny)是不是在圈子内,以及是否有积水
if(0<=nx&&nx<n&&0<=ny&&ny<m&&field[nx][ny]=='w')dfs(nx,ny);
}
}
return ;
}
void solve(){
int res=0;
for(int i=0;i<n;i++){
for(int j=0;i<m;j++){
if(field[i][j]==''w){
//从有w的地方开始dfs
dfs(i,j);
}
}
}
printf("%d\n",res);
}
用dfs的方法输出全排列
#include <iostream>
using namespace std;
int a[10],book[10],n;
void dfs(int step){
int i;
if(step==n+1){
for(i=1;i<=n;i++){
cout<<a[i];
}cout<<endl;
return ;
}
for(i=1;i<=n;i++){
if(book[i]==0){
a[step]=i;
book[i]=1;
dfs(step+1);
book[i]=0;
}
}
return ;
}
int main(){
cin>>n;
dfs(1);
getchar();
return 0;
}
dfs解组合问题
从1到n,A(r上)(n下);
#include <iostream>
#include <iomanip>
using namespace std;
int n,r,a[30];
void dfs(int step){
if(step==r+1){
for(int j=1;j<=r;j++)cout<<setw(5)<<a[j];
cout<<endl;
return ;
}
for(int i=a[step-1]+1;i<=n;i++){//i=a[step-1]+1把本次i赋值为a[step+1]的数值的下一个尤其重要
a[step]=i;
dfs(step+1);
}
return ;
}
int main(){
cin>>n>>r;
dfs(1);
return 0;
}
使用非递归的组合数
include <iostream>
#include <iomanip>
using namespace std;
int a[10],n,r,step=1;
int main(){
cin>>n>>r;
while(step){
if(step==r+1){/*>=*///个数满足条件输出
for(int i=1;i<=r;i++)cout<<setw(3)<<a[i];
cout<<endl;
step--;
continue;
}
if(!a[step]){//如果当前元素为0,就在上一个元素值的基础上+1,并向下移位
a[step]=a[step-1]+1;
step++;
continue;
}
if(a[step]+r-step<n){//判断 当前元素值+剩余格数 是否 大于最大值n
a[step++]++;//判断成立此位+1,向下移位 eg:123->124
continue;
}
//当前元素已不满足,当前为置0,回溯上一位
a[step--]=0;
}
return 0;
}
//3 2
// 1
// 1 2
// 1 3
// 1 0
// 2 0
// 2 3
// 2 0
// 0 0
//4 3
//1 0 0
//1 2 0
//1 2 3
//1 2 3
//1 2 4
//1 2 4
//1 3 0
//1 3 4
//1 3 4
//2 0 0
//2 3 0
//2 3 4
//2 3 4