P1443 马的便利(BFS)笔记

万恶之源
马的遍历

解法

这道题几乎就是一个裸的BFS,以马为起点遍历宽搜整个棋盘即可,层数即为到某点的最短步数,最后输出即可

若任意两个状态之间转移的代价都相同,那么BFS第一次访问到目标状态时,就是从起始状态到目标状态的最小代价。此题恰好移动代价都相同,如果不相同需要优先队列优化。

额外注意的点

  1. 如果使用getid(int x,int y)函数(一个自己定义将二维点压为一维点的函数),需要注意其中x的系数不能小于数据范围(400),否则会出现重复
int getid(int x,int y){
	return x*500+y-1;
//解压只需要x=id/n,y=id%n+1 
}
  1. 做这类类似用邻接矩阵存图的题一定要注意判断边界(包括马的坐标!!!),以及辨析长和宽。
bool check(int x,int y){
	if (x<1 || y<1) return false;
	if (x>n || y>m) return false;//这里不能是 x>m || y>n,辨析好变量的概念,养成好习惯,m是宽,n是长; 
	return true;
}
  1. 若题目的输出有宽度限制,不能简单的在输出数字后输出空格,应用限定符限制其宽度,c++的话,参考C++的cout高阶格式化操作
printf: %md (右对齐)
printf: %-md(左对齐)
cout:cout<<left<<setw(m)<<"输出的东西"<<endl;(左对齐)
cout<<right<<setw(m)<<"输出的东西"<<endl;(右对齐)

正题 BFS

BFS框架

queue<int> Q;
void BFS(int st) {
	Q.push(st);
	//接下来一系列初始化,图中往往要dis[st]=0以及memset
	while(Q.empty()==0) { //队列不为空就重复执行
		//某些预处理
		for (int i = 0; i < n; i++) { //枚举子节点 
			int now = Q.front();
			Q.pop();
			//对子节点进行操作
			if (/*如果子节点满足某些所需条件*/){
				//某些更新操作
				Q.push(i); //更新队列
			}
		}
	}
}

BFS的特点

  1. BFS有一个非常有用的特点,即逐层扩展的特点

  2. 若任意两个状态之间转移的代价都相同,那么BFS第一次访问到目标状态时,就是从起始状态到目标状态的最小代价

  3. 因为当把某一层的点全部遍历完后才会遍历到下一层的点(每次进队放在队的最末尾)

例如在网格图中求单源最短路,只需要从源点开始逐层扩展,d[i][j]表示从起点到点(i,j)的最小代价即可

需要注意的是

只有当状态两两之间相互转移的代价相同时,才能以第一次遍历到目标状态的代价作为最小代价

如果转移代价不相同,只有两条路可以走

使用优先队列,每次从队里拿出的状态不再是队头的状态,而是代价最小的

这就是堆优化的Dijkstra

允许反复进队,即某个状态第二次被访问到的时候,若此时代价更小则更新此状态的代价并再次进队,以更细其他状态,这种状态遇到好的数据,普通队列RE,优先队列TLE

posted @ 2021-11-01 17:12  tsrigo  阅读(68)  评论(0编辑  收藏  举报