电子学会五级-搜索-深搜
1 全排列问题
https://www.luogu.com.cn/problem/P1706
#include<bits/stdc++.h>
using namespace std;
//定义变量 n,当前排列记录数组,当前排列数字是否使用数组
int n,used[10],curRow[10];
void dfs(int k){
//满足退出条件 输出当前排列数组
if(k==n){
for(int i=1;i<=n;i++){
cout<<setw(5)<<curRow[i];
}
cout<<endl;
return;
}
// 1~n全部展开
for(int i=1;i<=n;i++){
//判断当前数字未使用进入
//当前数组是否使用,在定义数组是否设置
if(used[i]==0){
//设置
used[i]=1;
// 记录到当次排列数组
curRow[k+1]=i;
//递归dfs
dfs(k+1);
//恢复
used[i]=0;
}
}
}
int main(){
//输入
cin>>n;
//调用dfs 0开始 深度优先搜索
dfs(0);
return 0;
}
2 全排列
https://www.cnblogs.com/myeln/articles/16554432.html
#include<bits/stdc++.h>
using namespace std;
char s[10];
bool v[10];
char cur[10];
int n;
void dfs(int p){
if(p==n){
for(int i=0;i<n;i++){
printf("%c",cur[i]);
}
printf("\n");
return;
}
for(int i=0;i<n;i++){
if(!v[i]){
v[i]=true;
cur[p]=s[i];
dfs(p+1);
v[i]=false;
}
}
}
int main(){
scanf("%s",s);
n=strlen(s);//字符数组的有效长度
dfs(0);
return 0;
}
3 PERKET美食
https://www.luogu.com.cn/problem/P2036
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int v[N],ans=1e9;
int n;
struct sb{
int s;
int b;
}sbs[N];
/*
step 递归的层数
tots 到当前层累计的酸度
totb 到当前层累计的苦度
*/
void dfs(int step,int tots,int totb){
if(step==n){
if(tots!=0 && totb!=0){//排除一个都不选的情况
int temp=abs(tots-totb);//酸度和苦度差的绝对值
if(temp<ans){//取最小
ans=temp;
}
}
return;
}
dfs(step+1,tots*sbs[step].s,totb+sbs[step].b);//选择当前的
dfs(step+1,tots,totb);//不选当前的
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>sbs[i].s>>sbs[i].b;
}
dfs(0,1,0);
cout<<ans;
return 0;
}
4 自然数的拆分
https://www.luogu.com.cn/problem/P2404
#include <iostream>
using namespace std;
//输入要拆分的自然数和当次拆分过程中产生的数
int n, a[200];
//deep dfs深度每次加1 当次拆分的自然数 7 6
void dfs(int deep, int k){
//退出条件
if(k == 0){
if(deep == 2)//只有一个数时,不拆分
return;
// 1 ~ deep 循环打印 注意 +和换行
for(int i=1;i<deep;i++){
if(i==deep-1){
cout<<a[i]<<endl;
}else{
cout<<a[i]<<"+";
}
}
return;
}
// 每次对k个数进行递归拆分
for(int i = a[deep-1]; i <= k; i++){
//当前数放进数组
a[deep]=i;
//coding
k-=i;
//对去除当次的数,再进行递归拆分 dfs deep+1 , k-i
dfs(deep+1,k);
k+=i;
}
}
int main(){
cin >> n;
//从自然数1开始拆分
a[0] = 1;
dfs(1, n);
return 0;
}
5 组合的输出
https://www.cnblogs.com/myeln/articles/16554363.html
https://www.bilibili.com/video/BV1LV4y177G7/?spm_id_from=333.337.search-card.all.click&vd_source=29bdf11ae30b7aaca85ec74dc1b8e1ad
#include<bits/stdc++.h>
using namespace std;
int n,r;
bool v[50];
int f[50];
//now 用哪个数填 l填第几个空
void dfs(int now,int pos){
if(pos==r+1){//r个空填满
for(int i=1;i<=r;i++){
printf("%3d",f[i]);
}
printf("\n");
return;
}
for(int i=now;i<=n;i++){//从now下一个数填 避免重复
if(!v[i]){//本轮 此数未填过
v[i]=true;
f[pos]=i;
dfs(i+1,pos+1);
v[i]=false;
}
}
}
int main(){
cin>>n>>r;
dfs(1,1);
return 0;
}
6 八皇后 Checker Challenge
https://www.luogu.com.cn/problem/P1219
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=14;
int cnt,n;
//col列 pri 对角线 11 22 33 sec 对角线 13 22 31 ans[i]表示第i行 ans[i]列放入皇后
int col[maxn],pri[2*maxn],sec[2*maxn],ans[maxn];
void pr(){
for(int i=1;i<=n;i++){
if(i!=n)printf("%d ",ans[i]);
else printf("%d",ans[i]);
}
puts("");
}
void dfs(int dep){//递归到当前行
if(dep>n){
cnt++;
if(cnt<=3)pr();
return;
}//搜索到边界
for(int i=1;i<=n;i++){//循环每一列
//当前列未放 对角线1未放 对角线2未放
if(!col[i] && !pri[i-dep+maxn] && !sec[i+dep]){
ans[dep]=i;//记录结果
col[i]=1;pri[i-dep+maxn]=1;sec[i+dep]=1;
dfs(dep+1);
col[i]=0;pri[i-dep+maxn]=0;sec[i+dep]=0;//回溯
}
}
}
int main(){
scanf("%d",&n);
dfs(1);//从第一行开始搜索
printf("%d",cnt);
}
7 考前临时抱佛脚
https://www.luogu.com.cn/problem/P2392
#include<bits/stdc++.h>
using namespace std;
int s[5],q[5][21],qLeft,qRight,qmin,ans;
void dfs(int x,int y){//x表示科目 y表示当前做第几道题
if(y>s[x]){//科目x的题已经做完
//某科目题做完,比如是左脑和右脑一起完成,用时左右脑最慢的一个
//取所有左右脑组合方案中 时间最短的
qmin=min(qmin,max(qLeft,qRight));
return;
}
qLeft+=q[x][y];//左脑做
dfs(x,y+1);//做下一题
qLeft-=q[x][y];//回溯 恢复到左脑做之前
qRight+=q[x][y];//右脑做
dfs(x,y+1);//做下一题
qRight-=q[x][y];//回溯 恢复到右脑做之前
}
int main(){
cin>>s[1]>>s[2]>>s[3]>>s[4];
for(int i=1;i<=4;i++){
for(int j=1;j<=s[i];j++){
cin>>q[i][j];
}
qmin=0x3f3f3f;
dfs(i,1);//每个科目从第一个题开始
ans+=qmin;
}
cout<<ans;
}
8 LETTERS
https://www.cnblogs.com/myeln/articles/15360341.html
#include<bits/stdc++.h>
using namespace std;
int fx[4]={0,1,0,-1};
int fy[4]={-1,0,1,0};
//ans 记录最多步数 n 行 m列
int ans,n,m;
char a[200][200];//录入对应字符
bool p[50000];//一次走所有字符 不同的字符设置true
//x,y 走到当前坐标 z 已经走过的步数
int dfs(int x,int y,int z){
ans=max(ans,z);//每个字符走一次 记录走过的步数
for(int i=0;i<4;i++){
int xx=x+fx[i];
int yy=y+fy[i];
//在二维矩阵范围内找 没有找过的继续找
if(xx>0 && xx<=n && yy>0 && yy<=m && !p[a[xx][yy]]){
p[a[xx][yy]]=true;
dfs(xx,yy,z+1);
p[a[xx][yy]]=false;
}
}
}
int main(){
// memset(p,false,sizeof(p));
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
p[a[1][1]]=true;
dfs(1,1,1);
cout<<ans<<endl;
return 0;
}
9 红与黑-计算可到达的瓷砖数
https://www.cnblogs.com/myeln/articles/15361855.html
#include<bits/stdc++.h>
using namespace std;
const int MAXN=30;
char ipt[MAXN][MAXN];
bool v[MAXN][MAXN];
int dy[]={-1,1,0,0};
int dx[]={0,0,-1,1};//上下左右四个方向
//w水平 h竖直 x坐标 y坐标 sum累加次数
int w,h,x,y,sum;
void dfs(int yy,int xx){
for(int i=0;i<4;i++){
int yyy=yy+dy[i];
int xxx=xx+dx[i];
//在边界范围内 没有走过此位置
if(xxx>=0 && xxx<w && yyy>=0 && yyy<h && !v[yyy][xxx] && ipt[yyy][xxx]!='#'){
v[yyy][xxx]=true;//设置走过标识
sum++;//累加走过瓷砖数
dfs(yyy,xxx);//继续深入下一层搜索
}
}
}
int main(){
while(cin>>w>>h){
if(w==0 && h==0) break;// 0 0退出
memset(v,false,sizeof(v));// v默认 false
memset(ipt,' ',sizeof(ipt));//ipt 默认 ' '
sum=0;//累加走过瓷砖数从0开始累加
for(int i=0;i<h;i++){//行
for(int j=0;j<w;j++){//列
cin>>ipt[i][j];
if(ipt[i][j]=='@'){//找起始位置 记录行y 列 x
y=i,x=j;
}
}
}
v[y][x]=true;
sum++;//加入起始位置 不加有可能后面路堵死无法回来
dfs(y,x);
cout<<sum<<endl;//输出所有走过瓷砖数
}
}
/*
3 3
...
#@.
...
0 0
8
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
3 3
...
#@.
...
0 0
45
8
*/
10 1792 迷宫
https://www.cnblogs.com/myeln/articles/15361767.html
#include<bits/stdc++.h>
using namespace std;
const int MAXN=105;
char ipt[MAXN][MAXN];
bool v[MAXN][MAXN],flag;
int k,n;
int dy[]={-1,1,0,0};
int dx[]={0,0,-1,1};
int ha,la,hb,lb;
void dfs(int row,int col){
if(row==hb && col==lb){//走到b点 flag设为true 退出
flag=true;
return;
}
for(int i=0;i<4;i++){//四个方向递进
int row1=row+dy[i];
int col1=col+dx[i];
//在范围内 没有走过 可以走
if(row1>=0 && row1<n && col1>=0 && col1<n && !v[row1][col1] && ipt[row1][col1]=='.'){
v[row1][col1]=true;//设置走过
dfs(row1,col1);//继续递进
}
}
}
int main(){
cin>>k;
for(int p=0;p<k;p++){
cin>>n;
flag=false;
memset(ipt,' ',sizeof(ipt));
memset(v,false,sizeof(v));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>ipt[i][j];
}
}
cin>>ha>>la>>hb>>lb;
v[ha][la]=true;//先走起始点 起始点设置走过
if(ipt[ha][la]=='#' || ipt[hb][lb]=='#'){//起点 或重点是#号 无法走到
cout<<"NO"<<endl;
continue;
}
dfs(ha,la);//按行列逐层递进
if(flag){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
}
/*
2
3
.##
..#
#..
0 0 2 2
5
.....
###.#
..#..
###..
...#.
0 0 4 0
1
5
.....
###.#
..#..
###..
...#.
0 0 4 0
1
5
.....
###.#
..#..
##...
...#.
0 0 4 0
*/
11 单词接龙
https://www.luogu.com.cn/problem/P1019
#include<bits/stdc++.h>
using namespace std;
const int N=30;
int n,ans,mark[N];
string a[N];
char b;
string pd(string s1,string s2){
int len1=s1.length(),len2=s2.length();
for(int i=1;i<len1 && i<len2;i++){
if(s1.substr(len1-i,i)==s2.substr(0,i)){
return s1.substr(0,len1-i)+s2;
}
}
return "0";
}
void dfs(string curStr){
if(curStr.size()>ans){
ans=curStr.size();
}
for(int i=0;i<n;i++){
if(mark[i]==2) continue;
string s=pd(curStr,a[i]);
if(s!="0"){
mark[i]++;
dfs(s);
mark[i]--;
}
}
}
int main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
cin>>b;
for(int i=0;i<n;i++){
if(a[i][0]==b){
mark[i]++;
dfs(a[i]);
mark[i]--;
}
}
cout<<ans;
}
12 数独
https://www.luogu.com.cn/problem/P1784
参考
https://www.cnblogs.com/Roni-i/p/8512052.html
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int a[N][N];//输入数独初始数据
//r[i][num] i行num这个数字是否用过 c[j][num] j列num数字是否出现过
bool r[N][N],c[N][N],g[N][N];//g[idx][num] idx块 num数字是否出现过
void print(){
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
exit(0);
}
/*
从1行1列开始填数
*/
void dfs(int x,int y){
if(a[x][y]!=0){
if(x==9 && y==9){//行 列都搜索完 输出
print();
}
if(y==9){
dfs(x+1,1);//当列数为9 搜索下一行
}else{
dfs(x,y+1);//没到最后一列 搜索本行下一列
}
}
if(a[x][y]==0){
for(int i=1;i<=9;i++){//用1~9 数字填
int tmp=(x-1)/3*3+(y-1)/3+1;
if(!r[x][i] && !c[y][i] && !g[tmp][i]){
a[x][y]=i;//填数
r[x][i]=c[y][i]=g[tmp][i]=true;
if(x==9 && y==9){
print();
}
if(y==9){
dfs(x+1,1);
}else{
dfs(x,y+1);
}
a[x][y]=0;
r[x][i]=c[y][i]=g[tmp][i]=false;
}
}
}
}
int main(){
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
cin>>a[i][j];//输入
if(a[i][j]>0){//设置 行 列 块已填过此数字
int tmp=(i-1)/3*3+(j-1)/3+1;
r[i][a[i][j]]=c[j][a[i][j]]=g[tmp][a[i][j]]=true;
}
}
}
dfs(1,1);//从 1行1列开始填数
return 0;
}
13 [NOIP2002 普及组] 选数
https://www.luogu.com.cn/problem/P1036
#include<bits/stdc++.h>
using namespace std;
const int N=30;
//n k n个数选k个数 ans 累加 组合和为素数
int n,k,ans;
int a[N];
/*
判断素数 素数返回true 非素数返回false
*/
bool is_prime(int n){
bool flag=true;
for(int i=2;i*i<=n;i++){
if(n%i==0){
flag=false;
break;
}
}
return flag;
}
/*
往pos 位置填数
start从a[]数组哪个位置开始取数填 保证取不重复的数
sum 累加本次选出来的数
*/
void dfs(int pos,int start,int sum){
if(pos==k){//选出k个数
if(is_prime(sum)){//如果时素数
ans++;
}
return;
}
for(int i=start;i<n;i++){//从 a数组start位置开始取
//pos+1填下一个位置 i+1从i后面一个位置开始选
dfs(pos+1,i+1,sum+a[i]);//sum+a[i]累加本次选的数
}
}
int main(){
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>a[i];
}
dfs(0,0,0);
cout<<ans;
return 0;
}
14 素数环 Prime Ring Problem
https://www.luogu.com.cn/problem/UVA524
#include<bits/stdc++.h>
using namespace std;
const int N=16;
bool primeNum[N*2];
bool used[N*2];
int a[N*2];
/*
判断n是否为质数
*/
bool isPrime(int n){
bool flag=true;
for(int i=2;i*i<=n;i++){
if(n%i==0){
flag=false;
break;
}
}
return flag;
}
int n;
void dfs(int step){
if(step==n+1){
if(primeNum[a[n]+1]){
for(int i=1;i<n;i++){
cout<<a[i]<<" ";
}
cout<<a[n]<<endl;
}
}
for(int x=2;x<=n;x++){
//没使用过 且x和前一个元素和不是素数
if(!used[x] && primeNum[a[step-1]+x]){
a[step]=x;//x放入a数组
used[x]=true;//x标识已经使用
dfs(step+1);//递归放入下一个
a[step]=0;//回溯 a回溯 归0
used[x]=false;//x回溯 取消标识
}
}
}
int main(){
// 初始primeNum数组 打表
for(int i=2;i<=N*2;i++){
if(isPrime(i)){
primeNum[i]=true;
}
}
int cnt=1;//控制输入第几组数据
while(cin>>n){
if(cnt>=2){//第2组开始 前面打印换行
cout<<endl;
}
cout<<"Case "<<cnt++<<":"<<endl;
a[1]=1;//
dfs(2);
}
return 0;
}
15 P1928 外星密码
https://www.luogu.com.cn/problem/P1928
#include<bits/stdc++.h>
using namespace std;
/*
递归输入处理 返回[ ]内字符串
*/
string dfs(){
int k;
char c;
string s="",str="";
while(cin>>c){//循环输入字符
if(c=='['){//输入是 [
cin>>k;//[后面第一个是一个数字 表示到 ]前的数 循环几次
str=dfs();//返回[ ]内字符串
while(k--){//[ ]内字符串累加几次
s+=str;
}
}else if(c==']'){// 遇到 ] 返回str
return s;
}else{
s+=c;//非 [ ] 累加字符到s
}
}
}
int main(){
cout<<dfs();
return 0;
}
P1017 [NOIP2000 提高组] 进制转换
https://www.luogu.com.cn/problem/P1017
首先,要把 −15 转换成 −2 进制下的数,就要这么做。
最后,再反着读出来 110001 不就好了。
注意,余数只能为非负整数。
但是,c++ 中的 % 运算中:
(−1)%2=−1 ; (−3)%(−2)=−1
#include<bits/stdc++.h>
using namespace std;
int n,r;
void tenTother(int n,int r){
if(n==0){
return;
}
int m=n%r;
if(m<0){
m-=r;//由于r是负数 需要把m变成正数
n+=r;//模拟实现 短除法中 余数变成整数 需要被除数+r/r实现
}
if(m>=10){
m=m-10+'A';
}else{
m=m+'0';
}
tenTother(n/r,r);
cout<<(char)m;
}
int main(){
cin>>n>>r;
cout<<n<<"=";
tenTother(n,r);
cout<<"(base"<<r<<")";
return 0;
}
8 棋盘问题
https://www.cnblogs.com/myeln/articles/15362075.html
9 图的m着色问题
https://www.cnblogs.com/myeln/articles/16636195.html
14 靶形数独
https://www.luogu.com.cn/problem/P1074
通天之汉诺塔
https://www.luogu.com.cn/problem/P1760
Hanoi 双塔问题
https://www.luogu.com.cn/problem/P1096
DFS
https://www.bilibili.com/video/BV1bZ4y1y7Hd/?spm_id_from=333.788&vd_source=29bdf11ae30b7aaca85ec74dc1b8e1ad
小猫爬山
https://www.acwing.com/problem/content/description/167/
作者:newcode 更多资源请关注纽扣编程微信公众号
从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习