头文件和源文件的区别_memset头文件_头文件memory

关注我哟定期推送帐号信息学新闻,竞赛自主招生,信息学专业知识,信息学疑难解答,信息学训练营信息等诸多优质内容的微信平台,欢迎分享文章给你的朋友或者朋友圈!

大明老师

读完需要

28

分钟

速读仅需 14分钟

今天说下广度搜索优化的一些技巧,广度搜索的方式基本上是套模板,其实在套模板代码之外有一些优化的技巧,现在把广搜做为一个重点的专题,通过题目了解广度优先搜索如何优化。

头文件和源文件的区别_memset头文件_头文件memory

广度优先搜索优化

其实就是暴力的方式,优化的方向如何减少搜索的次数,加快搜索的效率。

减少搜索的次数,如何减少可以通过双向BFS。传统的BFS框架就是从起点开始向四周扩散,遇到终点时停止;而双向BFS则是从起点和终点同时开始扩散,当两边有交集的时候停止。

先看看传统的BFS,就是给个起始点,然后提供一个终点,一层一层的往下搜,一直搜到终点,这就是正常框架里面的单向BFS。

memset头文件_头文件和源文件的区别_头文件memory

双向的BFS,起始点和终止点同时双向扩散,举个例子:你去同学家见面比较远,你俩约一个地点离彼此比较近的地方,需要你和你同学同时都出发。

memset头文件_头文件memory_头文件和源文件的区别

双向如何确定最短路,就是彼此在想向搜索的时候,相遇的点彼此相遇,举个例子,起点访问过了,终点搜索的时候也访问过了,说明这个点已经被重合了,说明两个路径加起来就是最短的路径了。你和你同学彼此走过路之和就时候最短的路。

而双向BFS其实只遍历了半棵树就出现了交集,也就是找到了最短距离。但是双向BFS有个局限,必须知道终点在哪里,如果不知道终点在哪里肯定都没办法双向了。

既然是双向肯定是需要两个队列的,起始点一个队列,终止点一个队列。所以在原有的代码模板的基础上,需要有两个队列。其中在加个判断条件,点是否同时被两个人访问,如果被同时访问说明两个点就重合了,在队列的访问的加起来最短距离就出来了。

无论传统BFS还是双向BFS,无论做不做优化,从大 O 衡量标准来看,时间复杂度都是一样的,只能说双向BFS是一种trick,算法运行的速度会相对快一点,掌握不掌握其实都无所谓。最关键的是把BFS通用框架记下来,反正所有BFS算法都可以用它套出解法。

【题目描述】在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100×100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。

【输入】A、B两点的坐标。

【输出】最少步数。

头文件memory_memset头文件_头文件和源文件的区别

题目解析:走日的话是8个方向,走田的是4个方向,一共是12个方向。12个方向映射成12个坐标。

#include
using namespace std;
const int maxn = 1001;
char a[maxn] [maxn];
int vis [maxn] [maxn] ;
int d[12][2] ={ {2,1},{2,2},{1,2},{-1,2},{-2,2},{-2,1},{-2,-1},{-2,-2},{-1,-2},{1,-2},{2,-2},{2,-1} };//有12个方向
int n,m;
struct node{
 int x;
 int y;
 int step; 
}q[maxn*maxn];

void bfs(int x,int y) 
{
 int head=1;
 int tail=1;
 q[tail].x = x;
 q[tail].y = y;
 q[tail].step = 0;
 tail++;
 vis[x][y]=1
 while(head < tail)
 {
  int x0 = q[head].x;
  int y0 = q[head].y;
  int step = q[head].step;
  if(x0==1&&y0==1){
   cout<<step<<endl;
   break;
  }
  for(int i=0;i<12;i++)
  {
   int nx = x0 + d[i][0];
   int ny = y0 + d[i][1];
   if(nx>=1 && nx<100 &&ny >= 1 && ny < 100 && a[nx][ny] != '0'&& vis[nx][ny] != 1)
   {
    q[tail].x = nx;
    q[tail].y = ny;
    q[tail].step = step+1;
    tail++;
    vis[nx][ny]=1
   }
  }
  head++;
 }
}

int main()
{
 int xa,ya,xb, yb;
 memset(vis,0,sizeof(vis));
 cin>>xa>>ya>>xb>>yb;
 bfs(xa, ya);
 memset(vis,0,sizeof(vis));
 bfs(xb, yb);
 return 0;
}

memset头文件_头文件memory_头文件和源文件的区别

以下是对代码的解析:

引入头文件 ,用于包含常用的标准库。

使用命名空间 std。

定义常量 maxn,表示二维数组的最大大小。

声明二维字符数组 a,用于表示地图。

声明二维整数数组 vis,用于记录某个位置是否被访问过。

定义二维整数数组 dmemset头文件,表示12个方向的偏移量,用于马走日移动和田移动。

声明变量 n 和 m,表示行数和列数。

定义结构体 node,包含坐标 (x, y) 和步数 step,用于记录走到某个点所需要的步数。

声明队列 q,用于进行广度优先搜索。

定义函数 bfs,用于执行广度优先搜索算法。

在 main 函数中,初始化变量,并调用 bfs 函数两次,分别求解马走日和田的最短路径。

返回 0,表示程序运行结束。

该代码使用广度优先搜索算法来寻找马走日和田的最短路径。通过将起点加入队列,然后循环进行以下步骤:

【题目描述】农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0 5返回最短路为4,错误的,事实是3,S-2-4-T

memset头文件_头文件和源文件的区别_头文件memory

上面的牛和农夫的问题,通过双向BFS实现。

#include 
using namespace std;
const int maxn = 1000001 ;
int step;
void bfs(int sx, int ex)
{
 set<int>q1;
 set<int>q2;
 set<int>visted;
 set<int>tmp;
 q1.insert(sx);
 q2.insert(ex);
 while(q1.size() && q2.size())
 {
  tmp.clear();
  for(set<int>::iterator it = q1.begin(); it != q1.end(); it++)
  {
   int cur = *it;
   visted.insert(cur);
   
   if(q2.find(cur)!=q2.end())
   {
    cout<<step<<endl;
    return
   }
   for(int i = 1; i <= 3; i++)
   {
    int nc = cur;
    if(i==1) nc++;
    if(i==2) nc--;
    if(i==3
    {
     if(step%2!= 0)
     {
      if(nc%2 == 0
      {
       nc /= 2
      }
      else
      {
       continue ;
      }
     } 
     else
     {
      nc *= 2;
     }
    }
    if(nc >= 0 && nc <= 100000 && visted.find(nc) == visted.end())
    {
     tmp.insert(nc);
    }
   }

  }
  step++;
  q1 = q2;
  q2 = tmp; 
 }

int main()
{
 int n, k;
 cin>>n>>k;
 bfs(n,k);
 return 0;
}

头文件和源文件的区别_头文件memory_memset头文件

这段代码的功能是在一个数轴上,从起点 n 到终点 kmemset头文件,求解最短步数。以下是对代码解析:

引入头文件 ,用于包含常用的标准库。

使用命名空间 std。

定义常量 maxn,表示数组的最大大小。

声明变量 step,用于记录步数。

定义函数 bfs,用于执行广度优先搜索算法。

在 bfs 函数中,使用四个集合 q1、q2、 和 tmp,分别用于存储当前步数的起点集合、终点集合、已访问的集合和临时集合。

将起点 sx 加入集合 q1,将终点 ex 加入集合 q2。

在循环中,首先清空临时集合 tmp。

遍历集合 q1,对于其中的每个元素 cur,将其加入已访问的集合 。

如果终点集合 q2 中存在元素等于当前元素 cur,则输出步数 step 并返回。

否则,根据题目要求的三种操作,计算出相邻节点的坐标 nc。

如果相邻节点在规定范围内且未被访问过,则将其加入临时集合 tmp。

完成一轮循环后,步数 step 加一,将终点集合 q2 更新为临时集合 tmp,将起点集合 q1 更新为终点集合 q2。

在 main 函数中,读入起点 n 和终点 k,然后调用 bfs 函数求解最短步数。

返回 0,表示程序运行结束。

该代码使用广度优先搜索算法来寻找起点到终点的最短步数。通过使用两个集合 q1 和 q2 来交替存储当前步数的起点和终点,同时使用集合 来记录已访问的节点,以避免重复访问。在每一步中,根据题目要求的三种操作计算相邻节点的坐标,并将未访问过的相邻节点加入临时集合 tmp。当终点集合 q2 中存在与起点集合 q1 中相同的节点时,即找到最短路径,输出步数。

PS:在做题的时候,终点还是理解单向BFS,双向BFS受限比较多,单向BFS受限效率的话,就可以使用双向。不太建议,但是这种思维方式需要理解掌握。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注