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;
}