算法day1 dfs搜索2题
一 火星人
拿到这种类似于排序的,这个就好比如我们之前学习dfs基础的时候里面的指数型枚举
指数型枚举 数据与数据之间没有任何枚举,就比如选这个数字与不选 组合型枚举 数据与数据之间有联系,下一个数字不可以给上一个数字 排列型枚举 数据与数据之间有联系,下一个数字比上一个数字加1 所以我们刨析这个题目也就是这样我们以它的例子来讲解
也就是这样的一个排序方式
那我们这种,首先是每个数据与每个数据是有关系的,其次就是这个这个每次的对应的值都不可以给上一个,那么这种就是组合型枚举我们就用之前所学过的组合型枚举来敲一遍代码
#include<stdio.h> #include<algorithm> #include<cstring> using namespace std; const int N=10010; int m; //手指数 int n; //加的位数 int res=0; //记录加的次数 int ans[N]; //答案寄存数组 int mas[N]; //火星人所给的数字 int st[N]={0}; //表示状态数 bool return0 = false; void dfs(int x){ if(return0 == true){ return ; } if(x>m){ res++; if(res==n+1){ for(int i=1;i<=m;i++){ printf("%d ",ans[i]); } return0 = true; } return; } for(int i=1;i<=m;i++){ if(res==0){ i=mas[x]; } if(st[i]==0){ ans[x]=i; st [i]=1; dfs(x+1); ans[x]=0;//清理现场 st [i]=0; } } } int main(){ scanf("%d",&m); scanf("%d",&n); for(int i=1;i<=m;i++){ scanf("%d",&mas[i]); } dfs(1); return 0; }
我们这里写了一个减枝的操作前面的return0这个是用来减枝的,因为最后会有数据过不去
二 烤鸡
我们来分析这个题目,这个题目是有很多的烤鸡的调料,然后有10种调料,这每个调料都是有对应的3个不同重量的,然后我们输入一个重量,然后剩下的调料的重量要等于这个重量
我们这里就是指数型枚举,3个重量都有选择或者不选择,但是这里一定要有10种调料的种类
#include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N = 20; int n; int ret; int ans[N]; int mem[59055][N]; void dfs(int x,int sum){ if(sum>n) return; //减枝 if(x>10){ if(sum==n){ ret++; for(int i=1;i<=10;i++){ mem[ret][i]=ans[i]; } } return ; } for(int i=1;i<=3;i++){ ans[x]=i; dfs(x+1,sum+i); ans[x]=0; } } int main(){ scanf("%d",&n); dfs(1,0); printf("%d\n",ret); for(int i=1;i<=ret;i++){ for(int j=1;j<=10;j++){ printf("%d ",mem[i][j]); } printf("\n"); } return 0; }
总结:
我们在思考指数型枚举的时候,这里我们一般是不需要记忆数组的,因为我们就只有选择或者不选择,所以我们在递归的时候,就已经存在了选择和不选择,因为是深度优先搜索,最后要恢复现场,但是这个指数型有时候也是需要的,其实这里的烤鸡这个体题也是可以像我们之前写那个指数化枚举一样加一个记忆数组
我们在思考组合型枚举的时候,我们是需要记忆数组的,因为我们最开始分析的时候是由位置进行分析的,是否要放到这个位置,如果放了就要进行赋值,表示这个位置进行放了值,不会再在这里放值