蓝桥杯-dfs搜索模板题(一)
- P2089 烤鸡
- P1088 火星人
- P1149 火柴棒等式
- P2036 PERKET
- P1135 奇怪的电梯
- 结语
P2089 烤鸡
对于每个位置枚举数字
#include<bits/stdc++.h>using namespace std;const int N=10+10;int n;int arr[N];//临时方案 int res=0;//方案数int mem[1000000][N];//所有方案 void dfs(int x,int sum)//x是位数,sum是已选的总质量 {if(sum>n)return;if(x>10){if(sum==n){res++;for(int i=1;i<=10;i++){mem[res][i]=arr[i];}}return;}for(int i=1;i<=3;i++){arr[x]=i;dfs(x+1,sum+i);arr[x]=0;} }int main(){scanf("%d",&n);dfs(1,0);printf("%d\n",res);for(int i=1;i<=res;i++){for(int j=1;j<=10;j++){printf("%d ",mem[i][j]);}printf("\n");}return 0;}
P1088 火星人
本质也是对着位置枚举数字但是是在火星人给定的基础上,不然要搜索的太多了会爆
#include<bits/stdc++.h>
using namespace std;int n, m, res;
const int N = 10010;
int arr[N];
int mars[N];
bool st[N];
bool return0 = false;void dfs(int x)
{if (return0)return;//找到之后就不用往后搜了 //跟上面那个不一样,这个位数最多有10000太多了不能全部遍历 if (x > n){res++;if (res == m + 1){return0 = true;for (int i = 1; i <= n; i++){cout << arr[i] << ' ';}}return;}for (int i = 1; i <= n; i++){if (!res){i = mars[x];//从火星人给的开始枚举 }if (!st[i]){st[i] = true;arr[x] = i;dfs(x + 1);st[i] = false;arr[x] = 0;}}
}int main()
{cin >> n >> m;for (int i = 1; i <= n; i++)cin >> mars[i];dfs(1);return 0;
}
P1149 火柴棒等式
按照题目要求去搜索暴力。
经验之谈,最多应是711,多试几个可以试出来
#include<bits/stdc++.h>
using namespace std;
const int N= 10010;
int n;
int arr[N];
int res=0;
int nums[N]={6,2,5,5,4,5,6,3,7,6};//存火柴棍 int col(int x)//计算火柴棍数量
{if(nums[x]) return nums[x];else{int sumfire=0;while(x){sumfire+=nums[x%10];x/=10;}return sumfire;}
}void dfs(int x,int sum)
{if(sum>n) return ;if(x>3){if(arr[1]+arr[2]==arr[3]&&sum==n){res++;}return;}for(int i=0;i<=1000;i++) {arr[x]=i;dfs(x+1,sum+nums[i]);arr[x]=0;}
}int main()
{cin>>n;n-=4;for(int i=10;i<=1000;i++){nums[i]=nums[i%10]+nums[i/10];}dfs(1,0); cout<<res;return 0;}
P2036 PERKET
#include<bits/stdc++.h>
using namespace std;const int N=20;int n;int acid[N],bitter[N];
int res=1e9;//存答案
int st[N];//0未考虑 1选2不选void dfs(int x)
{if(x>n){bool has=false;int sum1=1;//酸度之积 int sum2=0;//苦度之和for(int i=1;i<=n;i++){if(st[i]==1){has=true;sum1*=acid[i];sum2+=bitter[i]; }}if(has) res=min(res,abs(sum1-sum2));//有得选才走,啥都不选返回1没价值return ; }//选st[x]=1;dfs(x+1);st[x]=0;//不选st[x]=2;dfs(x+1);st[x]=0;
}int main()
{cin>>n;for(int i=1;i<=n;i++)cin>>acid[i]>>bitter[i];dfs(1);cout<<res;return 0;
}
P1135 奇怪的电梯
每层只走一次的方案一定比每次重复走的方案好,用st来记录有没有走过。
这道题用以下代码只能过一部分,也是暴力的局限之处。得有更好的优化或其他方法
#include<bits/stdc++.h>
using namespace std;
const int N=10010;int n,A,B;
int evlt[N];
int res=1e9;
bool st[N];
//当前在x楼,按了cnt次按钮
void dfs(int x,int cnt)
{if(cnt>=res)return;if(x>n||x<0)return ;if(x==B){res=min(res,cnt);return ;} //上if(x+evlt[x]<=n&&!st[x+evlt[x]]){st[x+evlt[x]]=true;dfs(x+evlt[x],cnt+1); st[x+evlt[x]]=false;} //下if(x-evlt[x]>0&&!st[x-evlt[x]]){st[x-evlt[x]]=true;dfs(x-evlt[x],cnt+1); st[x-evlt[x]]=false;}}int main()
{cin>>n>>A>>B;for(int i=1;i<=n;i++){cin>>evlt[i];}dfs(A,0);if(res==1e9){cout<<-1;return 0;}cout<<res;return 0;}
结语
整理自链接: link