电子学会五级-搜索-深搜

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/

posted @ 2022-05-01 12:16  new-code  阅读(33)  评论(0编辑  收藏  举报