目录
1114. 棋盘问题 - dfs按行枚举
题目:
在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别
要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k 个棋子的所有可行的摆放方案数目
思路:
- 类似与n皇后问题,我们用dfs按行枚举 ,即每行放一个,我们只需要看这一行每一列是否被占即可
- 从第0行开始枚举,num记录已放好的棋子
- 在第i行枚举所有列j,如果该位置为棋盘区域且该列未被标记,则标记好
- 递归进入下一行,num+1
- 因为要枚举所有情况,因此dfs完要还原现场
- 要注意:因为棋子个数可能≤行数,因此有的行可以不放
import java.util.*;
class Main
{
static int N=10;
static char[][] g=new char[N][N];
static int[] col=new int[N]; //按行枚举 因此只需要看每列是否被占用即可
static int res,n,k;
public static void dfs(int x,int num)
{
if(num==k) //当棋子全部摆好
{
res++;
return;
}
if(x>=n) return; //越界
dfs(x+1,num); //可以这一行不放
for(int i=0;i<n;i++)
if(g[x][i]=='#'&&col[i]==0)
{
col[i]=1;
dfs(x+1,num+1);
col[i]=0;
}
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(true)
{
n=sc.nextInt();
k=sc.nextInt();
if(n==-1&&k==-1) break;
Arrays.fill(col,0);
for(int i=0;i<n;i++)
{
String s=sc.next();
for(int j=0;j<n;j++) g[i][j]=s.charAt(j);
}
res=0;
dfs(0,0); //从第0行开始dfs,摆好了0个棋子
System.out.println(res);
}
}
}
1096. 地牢大师 - 三维bfs求最短路
题目:
你现在被困在一个三维地牢中,需要找到最快脱离的出路!
地牢由若干个单位立方体组成,其中部分不含岩石障碍可以直接通过,部分包含岩石障碍无法通过
向北,向南,向东,向西,向上,向下移动,移动一个单元距离均需要一分钟。
你不能沿对角线移动,迷宫边界都是坚硬的岩石,你不能走出边界范围
可以逃脱输出最短逃生时间,否则输出Trapped!
思路:
采用三维数组跑一个bfs即可
import java.util.*;
class Main
{
static class Point
{
int x,y,z;
public Point(int x,int y,int z)
{
this.x=x;
this.y=y;
this.z=z;
}
}
static int N=110;
static char[][][] g=new char[N][N][N]; //长 宽 高
static int[][][] flag=new int[N][N][N];
static int[][][] dist=new int[N][N][N];
static int[] dx={1,-1,0,0,0,0},dy={0,0,-1,1,0,0},dz={0,0,0,0,1,-1};
static Point st,ed;
static int l,r,c;
public static int bfs()
{
for(int i=0;i<110;i++)
for(int j=0;j<110;j++)
{
Arrays.fill(dist[i][j],-1);
Arrays.fill(flag[i][j],0);
}
Queue<Point> q=new LinkedList<>();
q.offer(st);
flag[st.x][st.y][st.z]=1;
dist[st.x][st.y][st.z]=0;
while(!q.isEmpty())
{
var t=q.poll();
for(int i=0;i<6;i++)
{
int nx=t.x+dx[i],ny=t.y+dy[i],nz=t.z+dz[i];
if(nx<0||nx>=r||ny<0||ny>=c||nz<0||nz>=l) continue; //越界
if(g[nx][ny][nz]=='#'||flag[nx][ny][nz]==1) continue;
dist[nx][ny][nz]=dist[t.x][t.y][t.z]+1;
flag[nx][ny][nz]=1;
q.offer(new Point(nx,ny,nz));
}
}
return dist[ed.x][ed.y][ed.z];
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(true)
{
l=sc.nextInt();r=sc.nextInt();c=sc.nextInt();
if(l==0&&r==0&&c==0) break;
for(int k=0;k<l;k++)
{
for(int i=0;i<r;i++)
{
String s=sc.next();
for(int j=0;j<c;j++)
{
g[i][j][k]=s.charAt(j);
if(g[i][j][k]=='S') st=new Point(i,j,k);
else if(g[i][j][k]=='E') ed=new Point(i,j,k);
}
}
}
int res=bfs();
if(res==-1) System.out.println("Trapped!");
else System.out.printf("Escaped in %d minute(s).\n",res);
}
}
}
1100. 抓住那头牛 - 一维bfs求最短路
题目:
思路:
用bfs枚举所有方案(-1,+1,*2)
为什么bfs可以求最短路?
因为bfs是一层一层向外拓展,那么每搜一次(即入队一层),路径长度+1,所以最先到终点的那条路径一定是最短的,而且因为走过的点有标记,所以每个点只会遍历一次,则遍历结束后就能知道最短路,所以用BFS可以求任意起点到终点的最短路径
import java.util.*;
class Main
{
static int N=100110;
static int[] dist=new int[N];
static int n,k;
public static int bfs()
{
Queue<Integer> q=new LinkedList<>();
Arrays.fill(dist,-1);
q.offer(n);
dist[n]=0;
while(!q.isEmpty())
{
var t=q.poll();
if(t==k) return dist[t];
int[] dx={-1,1,t};
for(int i=0;i<3;i++)
{
int nx=t+dx[i];
if(nx<0||nx>100000) continue;
if(dist[nx]!=-1) continue;
dist[nx]=dist[t]+1;
q.offer(nx);
}
}
return -1;
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
n=sc.nextInt();k=sc.nextInt();
System.out.print(bfs());
}
}
4218. 翻转 - 递推
和费解的开关是同类题,详细见下方链接!
【蓝桥杯集训5】递推专题(3 / 3)_Roye_ack的博客-CSDN博客
题目:
思路:
- 因为每一行的状态都能决定下一行的状态,所以先枚举第0行的所有情况
- 则000……0~111……1一共有2^m种情况
- 根据第0行的状态推出第1 ~ n-1行的状态
- 目标是获得全0矩阵,则枚举到每一行,遇到1时就改变该状态
- 第i行的状态由第i+1行的状态决定
- 最后检查最后一行的状态,如果最后一行全为0,说明方案可行,更新最小操作数方案
- 否则当最后一行有1,则方案不可行
import java.util.*;
class Main
{
static int N=20;
static int[][] g=new int[N][N],copy=new int[N][N],ans=new int[N][N];
static int[][] cur=new int[N][N]; //标记翻转的位置
static int[] dx={0,0,0,1,-1},dy={0,1,-1,0,0};
static int m,n,cnt;
public static void turn(int x,int y)
{
for(int i=0;i<5;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=m) continue;
g[nx][ny]^=1;
}
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
n=sc.nextInt();m=sc.nextInt();
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) copy[i][j]=sc.nextInt();
int res=0x3f3f3f3f;
for(int op=0;op<(1<<m);op++) //枚举第一行的所有情况000……0~111……1一共2^m种情况
{
//取出原矩阵
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) g[i][j]=copy[i][j];
//重置cur矩阵
for(int i=0;i<n;i++) Arrays.fill(cur[i],0);
int cnt=0; //记录翻转次数
for(int i=0;i<m;i++)
if((op>>i&1)==1)
{
cnt++;
turn(0,i);
cur[0][i]=1;
}
for(int i=0;i<n-1;i++) //递推出第1~n-1行的状态 如果要改变第i行的某个状态,需要改变i+1行
for(int j=0;j<m;j++)
if(g[i][j]==1)
{
turn(i+1,j);
cnt++;
cur[i+1][j]=1;
}
//看最后一行状态是否符合全0 符合则有方案 不符合则impossible
boolean f=true;
for(int i=0;i<m;i++)
if(g[n-1][i]==1)
{
f=false;
break;
}
if(f&&res>cnt) //如果符合则更新最小答案
{
res=cnt;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++) ans[i][j]=cur[i][j];
}
}
if(res==0x3f3f3f3f) System.out.print("IMPOSSIBLE");
else
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
System.out.print(ans[i][j]+" ");
System.out.println();
}
}
}
}
4219. 找倍数 - dfs按位枚举 / bfs
题目:
给定一个正整数 n,请你找到一个它的非零倍数 m
要求 m 中只包含数字 0 或 1,并且总位数不超过 100 位
输出任意合法数即可
1、dfs
import java.util.*;
class Main
{
static int n;
static boolean f;
public static void dfs(int u,long sum)
{
if(f||u>=19) return; //如果已经找到答案或sum值太大
if(sum%n==0)
{
System.out.println(sum);
f=true;
return;
}
dfs(u+1,sum*10);
dfs(u+1,sum*10+1);
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(true)
{
n=sc.nextInt();
if(n==0) break;
f=false;
dfs(0,1);
}
}
}
2、bfs
import java.util.*;
class Main
{
static int n;
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(true)
{
n=sc.nextInt();
if(n==0) break;
Queue<Pair> q=new LinkedList<>();
q.offer(new Pair("1",1));
while(!q.isEmpty())
{
var t=q.poll();
if(t.sum==0) {System.out.println(t.s);break;}
q.offer(new Pair(t.s+"1",(t.sum*10+1)%n));
q.offer(new Pair(t.s+"0",(t.sum*10)%n));
}
}
}
}
class Pair
{
String s;
long sum;
Pair(String s,long sum)
{
this.s=s;
this.sum=sum;
}
}
4220. 质数路径 - bfs求最短路 - 未ac正在找bug!!!
题目:
思路:
将每一位数换成除自身之外的0~9的数,检查是否为质数
如果为质数则记录操作次数,并入队
如果枚举到结果,则返回记录的操作次数
import java.util.*;
class Main
{
static int N=10010;
static int[] dist=new int[N];
static int[] st=new int[N];
static int[] prime=new int[N];
public static void get_prime()
{
prime[0]=1;
prime[1]=1;
for(int i=2;i<N;i++)
if(prime[i]==0)
{
for(int j=i+i;j<N;j+=i) prime[j]=1;
}
}
public static boolean isprime(int x)
{
if(x<2) return false;
for(int i=2;i<=x/i;i++)
if(x%i==0) return false;
return true;
}
public static int bfs(int a,int b)
{
Queue<Integer> q=new LinkedList<>();
Arrays.fill(st,0);
Arrays.fill(dist,0);
q.offer(a);
st[a]=1;
while(!q.isEmpty())
{
var t=q.poll();
if(t==b) return dist[b];
int[] d={t/1000,t/100%10,t/10%10,t%10};
for(int i=0;i<4;i++)
{
int x=d[i];
for(int j=0;j<10;j++)
if(j!=x)
{
d[i]=j;
int sum=d[0]*1000+d[1]*100+d[2]*10+d[3];
if(st[sum]==0&&isprime(sum))
{
st[sum]=1;
q.offer(sum);
dist[sum]=dist[t]+1;
}
if(sum==b) return dist[sum];
}
d[i]=x; //还原回去
}
}
return -1;
}
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
while(t-->0)
{
int a=sc.nextInt(),b=sc.nextInt();
System.out.println(bfs(a,b));
}
}
}