算法学习
目录
广度搜索模板
int dx[4]={1,0,-1,0}; int dy[4]={0,1,0,-1};//定义坐标偏移量 int sx,sy;//起点x、y坐标 int vis[350][350];//vis数组用来防止同一个点访问多次,true表示已访问,false表示为访问 que.push((point){sx,sy,0});//将起点坐标放入队列,初始步数为0 while(!que.empty())//只要还有可到达点就继续访问,知道榨干它 { point f=que.front();//提取出队头 que.pop();//切记!一定要记得将队头扔掉,否则会死循环 if(a[f.x][f.y]=='=')//如果当前点就是终点 { cout<<f.t;//输出它,结束~ return 0; } for(int i=0;i<=3;i++)//遍历其上下左右相邻的点 { //下面与深搜基本一样 int nx=x+dx[i];//获取相邻点的x、y坐标 int ny=y+dy[i]; if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[nx][ny]!='#'&&!vis[nx][ny])//判断是否越界、是否撞墙、当前点是否已经被访问过 { que.push((point){nx,ny,f.t+1});//可以走便将其放入队列 vis[nx][ny]=true;//标记当前点已经走过 } } }
1.马走日
1.bfs--队列元素设置:x,y,s;横纵坐标和step;
2.方向数组:马走日,8个方向;
3.队列初始化&&head,tail:x,y,s;
4.扩充队尾tail++;
5.起点标记;
6.剪枝干:边界,标记,障碍
7.for循环设置:8个方向选择
8.队首选择某方向走下一步
9.赋给队尾tx,ty,s+1;
10.扩充队尾tail++;
11.head++;出队(tail将8个方向尝试后)
#include<stdio.h> #include<stdlib.h> #include<math.h> struct node { int x; //横坐标 int y; //纵坐标 int s; //步数step }; int main() { struct node que[400*400+10]; //结构体,地图至少大小400*400 int a[401][401]; int book[401][401]; int bx[]= {1,1,-1,-1,2,2,-2,-2};//马走日 int by[]= {2,-2,2,-2,1,-1,1,-1}; int ans[401][401]; //到达每一点所需步数 int head=1,tail=1; //初始化head,tail; int n,m,sx,sy; scanf("%d %d %d %d",&n,&m,&sx,&sy); que[tail].x=sx; //初始化que队列 que[tail].y=sy; que[tail].s=0; //此时位于起点,还没走,step=0; tail++; //head=1,tail=2; book[sx][sy]=1; //标记起点 memset(ans,-1,sizeof(ans)); //初始化为-1 ans[sx][sy]=0; //起点为0 //int flag=0; while(head<tail) //循环队列条件head<tail { for(int k=0;k<8;k++) //for循环8个方向 { int tx=que[head].x+bx[k]; //注意是que【head】 int ty=que[head].y+by[k]; //x,y往其中一个方向走 if(tx<1||ty<1||tx>n|ty>m)continue; //边界 if(a[tx][ty]==1||book[tx][ty]==1)continue; //标记和障碍,此题无障碍 book[tx][ty]=1; //标记,但不用取消标记,宽搜每个点只入队一次; que[tail].x=tx; //head移给tail que[tail].y=ty; //head移给tail que[tail].s=que[head].s+1; //tail步数比head多1 ans[tx][ty]=que[tail].s; // 步数赋给ans保存 tail++; //队列后移 } head++; //出队操作,可尝试方向尝试完后跳出循环; } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { printf("%d ",ans[i][j]); } printf("\n"); } return 0; }
2.填涂游戏
P1162 填涂颜色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
https://www.luogu.com.cn/problem/P1162
1.关键点:连通块,在已给图形上再套一圈(1-n)--(0,n+1);(逆向思维)已标记的0为不涂色的,未标记的0为涂色的。
2.队列初始化&&head=tail=1:x,y,s=0;(二维数组x,y)+标记起点
3.扩充队尾tail++;
4.for循环设置:que[head]选择4个方向
5.插点入队:tx,ty,s+1
6.扩充队尾tail++;
7.该点循环方向选择结束,入队:head++;
#include<stdio.h> struct note { int x; int y; int s; } que[2000]; int main() { int n,i,j; int a[40][40]= {0}; //int book[40][40]; scanf("%d",&n); for(i=1; i<=n; i++) //输入内圈(1,n),整体为(0,n+1),构造连通块; for(j=1; j<=n; j++) { scanf("%d",&a[i][j]); } int bx[]= {0,0,1,-1}; int by[]= {1,-1,0,0}; int head=1,tail=1; que[tail].x=1; que[tail].y=1; que[tail].s=0; tail++; a[0][0]=2; //起点标记 while(head<tail) { for(i=0; i<=3; i++) { int tx=que[head].x+bx[i]; //四个方向 int ty=que[head].y+by[i]; if(tx<0||ty<0||tx>n+1||ty>n+1)continue;//排除边界,此时边界为0,n+1; //if(a[tx][ty]==-1)continue; if(a[tx][ty]==0) //为空0时 { a[tx][ty]=2; que[tail].x=tx; que[tail].y=ty; que[tail].s=que[head].s+1; tail++; } } head++; } for(i=1; i<=n; i++) { for(j=1; j<=n; j++) { if(a[i][j]==0)//未标记输出2 printf("2 "); else if(a[i][j]==2) //标记输出0 printf("0 "); else printf("1 ");//1输出1 } printf("\n"); } return 0; }