简单搜索

A

求总的方案数,很显然用dfs可以写。

每摆一个棋子,将会使得一行一列都不能再摆。

那么用一个mark1数组表示有哪些行被摆了,用mark2表示那些列被摆了。

在dfs的时候,进入新状态的时候记得把行列标记,在退回该节点的时候别忘了把该行该列恢复。

一直到摆了k个棋子为止,注意递归边界。

这题有一个问题,如果每一次层递归,你都看看每一个点是否可以摆的话,将会记录重复的数据。

比方说先摆(1,1)再摆(2,2)和先摆(2,2)再摆(1,1)将会重复。

为了避免这样,有两种办法。

一种,先算出重复以后的数量,再把重复的除掉。

另一种,我搜索的时候就注意,从一层递归时,只取在他之后的节点进入,保证有序,那么就不会出现重复了。

PS.如果这题按照行的顺序来枚举要摆的位置,然后每次进入节点以后都从下一行开始搜(保证了有序),甚至我们可以不用标记行了。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int n,k,ans;
char str[10][10];
bool mark1[10],mark2[10];

bool judge(int x,int y){
	if(mark1[x]||mark2[y])return false;
	if(str[x][y]=='.')return false;
	return true;
}

void dfs(int x,int y,int num){
	if(num==k){
		ans++;
		return;
	}
	for(int i=x+1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(judge(i,j)){
				mark1[i]=true;
				mark2[j]=true;
				dfs(i,j,num+1);
				mark1[i]=false;
				mark2[j]=false;
			}
		}
	}
}

int main(){
	
	while(~scanf("%d%d",&n,&k)){
		if(n==-1&&k==-1)break;
		memset(mark1,0,sizeof(mark1));
		memset(mark2,0,sizeof(mark2));
		ans=0;
		for(int i=1;i<=n;i++)
			scanf("%s",str[i]+1);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(str[i][j]=='#'){
					mark1[i]=true;
					mark2[j]=true;
					dfs(i,j,1);
					mark1[i]=false;
					mark2[j]=false;
				}
			}
		}
		printf("%d\n",ans);
	}
	return 0;
} 

B

一个最简单的迷宫问题。

不过把状态改成了三维的。

写法和二维基本一致。

#include<queue>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=35;
int sx,sy,sz,ex,ey,ez,l,n,m,step[N][N][N];
char map[N][N][N];

struct node{
	int x,y,z;
};
queue<node>que;

int dx[]={0,0,0,0,1,-1};
int dy[]={0,0,1,-1,0,0};
int dz[]={1,-1,0,0,0,0};

bool judge(node p){
	if(p.x<=0||p.x>l)return false;
	if(p.y<=0||p.y>n)return false;
	if(p.z<=0||p.z>m)return false;
	if(step[p.x][p.y][p.z]!=-1)return false;
	if(map[p.x][p.y][p.z]=='#')return false;
	return true;
}


void BFS(){
	while(!que.empty())que.pop();
	que.push((node){sx,sy,sz});
	step[sx][sy][sz]=0;
	while(!que.empty()){
		node cur=que.front();
		que.pop();
		
		//cout<<"xyz:"<<cur.x<<" "<<cur.y<<" "<<cur.z<<endl;
		
		
		for(int i=0;i<6;i++){
			node nxt=(node){cur.x+dx[i],cur.y+dy[i],cur.z+dz[i]};
			if(judge(nxt)){
				step[nxt.x][nxt.y][nxt.z]=step[cur.x][cur.y][cur.z]+1;
				que.push(nxt);
			}
		}
	}

}

int main(){
	
	while(true){
		memset(step,-1,sizeof(step));
		scanf("%d%d%d",&l,&n,&m);
		
		if(l==0&&n==0&&m==0)break;
		
		for(int i=1;i<=l;i++)
			for(int j=1;j<=n;j++)
				scanf("%s",map[i][j]+1);
		
		for(int i=1;i<=l;i++)
			for(int j=1;j<=n;j++)
				for(int k=1;k<=m;k++){
					if(map[i][j][k]=='S'){
						sx=i,sy=j,sz=k;	
					}
					if(map[i][j][k]=='E'){
						ex=i,ey=j,ez=k;
					}
				}
		
		BFS();
		if(step[ex][ey][ez]!=-1){
			printf("Escaped in %d minute(s).\n",step[ex][ey][ez]);
		}else{
			puts("Trapped!");
		}
	}
	return 0;

}

C

可以算是一个一维的迷宫,不过有限定的行走方式(而非单单上下左右)。

行走方式有三种,一种+1,一种-1,一种*2。

注意状态的转移,注意边界即可。

#include<queue>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=1e9;
const int N=1e5+5;
int n,k,step[N];

queue<int>que;

void BFS(){
	step[n]=0;
	que.push(n);
	while(!que.empty()){
		int cur=que.front();
		que.pop();
		if(cur*2<=1e5&&step[cur*2]==INF){
			step[cur*2]=step[cur]+1;
			que.push(cur*2);
		}
		if(cur+1<=1e5&&step[cur+1]==INF){
			step[cur+1]=step[cur]+1;
			que.push(cur+1);
		}
		if(cur-1>=0&&step[cur-1]==INF){
			step[cur-1]=step[cur]+1;
			que.push(cur-1);
		}
	}
}

int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<=1e5;i++)step[i]=INF;
	BFS();
	printf("%d\n",step[k]);
	return 0;

}

E

题目:告诉你一个数n,要求你找到你个只有0和1组成的数,可以整除n;

就是dfs ,每次两种情况搜,*10和*10+1(这样子就可以构造出所有只包含01的数字)

#include<stdio.h>
int n;
int flag;
void dfs(long long cur,int k){
	if(k==19){
		return ;
	}
	if(flag){
		return ;
	}
	if(cur%n==0){
		flag=1;
		printf("%lld\n",cur);
		return ;
	}
	dfs(cur*10,k+1);
	dfs(cur*10+1,k+1);
}
int main(){
	while(true){
         scanf("%d",&n);
		if(n==0){
			break;
		}
		flag=0;
		dfs(1,0);
	}
	return 0;
}

F

状态就是当前的数字

一个状态能够转移到的状态要满足两个条件

1 和原状态相差一个数字

2 是个素数

那么对于一个状态,我们枚举所有和他差一个数字的状态),然后看看它们是不是素数,如果是,那么就转移。

素数可以提前筛好。

#include<queue>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm> 
using namespace std;
const int N=10005;
const int INF=1e9;
int T,x,y;
bool is_prime[N];
queue<int>que;
int ans[N];

void Init(){
	for(int i=1;i<=10000;i++)is_prime[i]=true;
	is_prime[1]=false;
	for(int i=2;i<=10000;i++){
		if(is_prime[i]){
			for(int j=i*i;j<=10000;j+=i)is_prime[j]=false;
		}
	}
}

void check_in(int nxt,int res){
	if(ans[nxt]==INF&&is_prime[nxt]){
		ans[nxt]=res+1;
		que.push(nxt);
	}
}

void BFS(){
	while(!que.empty())que.pop();
	que.push(x);
	ans[x]=0;
	while(!que.empty()){
		int cur=que.front();
		que.pop();
		for(int i=1;i<=9;i++)
			check_in(cur%1000+i*1000,ans[cur]);
		for(int i=0;i<=9;i++){
			check_in(cur/1000*1000+cur%100+i*100,ans[cur]);
			check_in(cur/100*100+cur%10+i*10,ans[cur]);
			check_in(cur/10*10+i,ans[cur]);
		}
	}
}

int main(){
	scanf("%d",&T);
	
	
	Init();
	while(T--){
		for(int i=1;i<=10000;i++)ans[i]=INF;
		scanf("%d%d",&x,&y);
		BFS();
		printf("%d\n",ans[y]);
	}
	return 0;
}

K

二维的迷宫问题,要求输出路径。

那么相比于之前的问题,难点在于输出路径。

在记录状态时,除了记录当前点的坐标以外,再记录一个信息——当前状态是由哪一个状态转移过来的。

如果使用数组模拟队列来BFS的话,可以直接记录转移到当前节点的上一个节点在队列中的下标,那么就可以方便得到上一个状态。

如果用的时STL中的queue,那么可以记录上一个节点的xy,之后用(px[x][y],py[x][y])表示转移到(x,y)的上一个节点。

#include<queue>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

bool mark[6][6];
int mp[6][6],px[6][6],py[6][6];
struct node{
	int x,y;
};
queue<node>que;

void check_in(int nx,int ny,int prex,int prey){
	if(nx>5||ny>5||nx<1||ny<1)return;
	if(mark[nx][ny])return;
	if(mp[nx][ny]==1)return;
	mark[nx][ny]=true;
	px[nx][ny]=prex;
	py[nx][ny]=prey;
	que.push((node){nx,ny});
}

void BFS(){
	que.push((node){1,1});
	mark[1][1]=true;
	while(!que.empty()){
		node cur=que.front();
		que.pop();
		int nx=cur.x,ny=cur.y;
		
		check_in(nx-1,ny,nx,ny);
		check_in(nx+1,ny,nx,ny);
		check_in(nx,ny-1,nx,ny);
		check_in(nx,ny+1,nx,ny);
	
	}


}

void Print(int x,int y){
	if(x==1&&y==1)return;
	Print(px[x][y],py[x][y]);
	
	printf("(%d, %d)\n",x-1,y-1);
	
}

int main(){
	for(int i=1;i<=5;i++)
		for(int j=1;j<=5;j++)
			scanf("%d",&mp[i][j]);
	
	memset(mark,0,sizeof(mark));
	
	BFS();
	
	printf("(0, 0)\n");
	Print(5,5);
	
	
	return 0;
}

L

和之前博客里讲的第二种dfs几乎一样(flood-filled)

直接给一篇题解

https://blog.csdn.net/galesaur_wcy/article/details/79500223

M

推荐一篇题解

https://blog.csdn.net/ssyitwin/article/details/80396931

N

题意:从Y出发到达@再到达M的最短路(@有多个)

分别从Y和M两个点为起点跑两边BFS,预处理出Y为起点到达其他点的最短距离和从M为起点到达其他点的最短距离。

之后枚举每一个@,找到Y到这个@加上M到这个@的最短距离之和的最小值。

#include<map>
#include<queue>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=205;
const int INF=1e9;
int n,m,sx,sy,cnt[2][N][N];
char str[N][N];

struct node{
	int x,y;
};
queue<node>que;

int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};

bool judge(node p){
	if(p.x<=0||p.x>n||p.y<=0||p.y>m)return false;
	if(str[p.x][p.y]=='#')return false;
	return true;
}


void BFS(int t){
	while(!que.empty())que.pop();
	que.push((node){sx,sy});
	cnt[t][sx][sy]=0;
	while(!que.empty()){
		node cur=que.front();
		que.pop();
		for(int i=0;i<4;i++){
			node nxt=(node){cur.x+dx[i],cur.y+dy[i]};
			if(judge(nxt)&&cnt[t][nxt.x][nxt.y]==-1){
				cnt[t][nxt.x][nxt.y]=cnt[t][cur.x][cur.y]+1;
				que.push(nxt);
			}
		}
	}
}

int main(){
	while(~scanf("%d%d",&n,&m)){
		memset(cnt,-1,sizeof(cnt));
		
		for(int i=1;i<=n;i++)
			scanf("%s",str[i]+1);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(str[i][j]=='Y'){
					sx=i,sy=j;
					BFS(0);		
				}
				if(str[i][j]=='M'){
					sx=i,sy=j;
					BFS(1);
				}
			}
		}
		
		int ans=INF;
		
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(str[i][j]=='@'){
					if(cnt[0][i][j]!=-1&&cnt[1][i][j]!=-1){
						ans=min(ans,cnt[0][i][j]+cnt[1][i][j]);
					}
				}
			}
		}
		printf("%d\n",ans*11);
	}
	return 0;	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值