暴力搜索

看到这道题的第一反应就是直接上$bfs$啦,也没有想到什么更加优秀的算法。

然后就是$15$分钟打了$70$分,有点震惊,纯暴力诶,这么多白给分嘛,太划算了,这可是$D2T3$诶。

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 using namespacestd;10 #define ll long long

11 #define INF 0x3f3f3f3f

12 #define N 35

13 intrd()14 {15 int f=1,s=0;char c=getchar();16 while(c'9'){if(c=='-') f=-1;c=getchar();}17 while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();}18 return f*s;19 }20 structnode{21 int mx,my,nx,ny;//空格的位置,初始棋子现在的位置

22 int stp;//步数

23 };24 intn,m,q;25 intmp[N][N];26 intex,ey,sx,sy,tx,ty;27 queueQ;28 const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};29 boolvis[N][N][N][N];30 bool check(int xx,intyy)31 {32 if(xx<0||xx>n||yy<0||yy>m||mp[xx][yy]==0) return 0;33 return 1;34 }35 intmain()36 {37 n=rd(),m=rd(),q=rd();38 for(int i=1;i<=n;i++)39 for(int j=1;j<=m;j++)40 mp[i][j]=rd();41 while(q--)42 {43 ex=rd(),ey=rd(),sx=rd(),sy=rd(),tx=rd(),ty=rd();44 if(sx==tx&&sy==ty)45 {//下面村答案是在拓展节点之后存 所以这里要特判

46 puts("0");//如果取出时存答案就不用特判(好像也不用break很多层了

47 continue;48 }49 memset(vis,0,sizeof(vis));50 bool flag=0;51 while(!Q.empty()) Q.pop();52 node s;s.mx=ex,s.my=ey,s.nx=sx,s.ny=sy,s.stp=0;53 vis[ex][ey][sx][sy]=1;54 Q.push(s);55 while(!Q.empty())56 {57 s=Q.front();Q.pop();58 for(int i=0;i<4;i++)59 {60 node nxt;61 nxt.mx=s.mx+dx[i],nxt.my=s.my+dy[i];62 if(!check(nxt.mx,nxt.my)) continue;63 if(nxt.mx==s.nx&&nxt.my==s.ny) nxt.nx=s.mx,nxt.ny=s.my;64 else nxt.nx=s.nx,nxt.ny=s.ny;65 nxt.stp=s.stp+1;66 if(nxt.nx==tx&&nxt.ny==ty)67 {68 flag=1;69 printf("%d\n",nxt.stp);70 break;71 }72 if(vis[nxt.mx][nxt.my][nxt.nx][nxt.ny]) continue;73 Q.push(nxt);74 vis[nxt.mx][nxt.my][nxt.nx][nxt.ny]=1;75 }76 if(flag) break;77 }78 if(flag) continue;79 else puts("-1");80 }81 return 0;82 }

Code

正解分析

纯暴力的$bfs$会超时,是因为搜索了很多无用状态:真正有用的状态其实是起点格子走的状态,但是这道题用搜索方便转移的却是空白格子,因为题目的规则是空白格子可以移动(相当于和旁边的格子交换位置)。

只有起点格子在空白格子四周起点格子才能动,所以应该是尽量让空白格子往起点格子周围跑,而不是毫无目的地乱跑,空白格子在乱跑的时候实际上拓展了很多无用节点。

那么,就先用一个$bfs$预处理出空白格子到达起点格子四周的距离,然后再从四周分别开始走,取最小的。

从四周开始走的时候还是不考虑暴搜(会产生多余状态),我们只管有用的状态。还是这个道理:起点格子是要依托于空白格子才能够移动的,所以状态要保持空白格子一直在起点格子四周。

那么定义状态$(i,j,k)$表示起点格子的坐标为$(i,j)$,空白格子在它的$k$方向(也即是坐标为$(i+dx[k],j+dy[k])$)。

考虑转移到后继状态:

1.可以是起点格子通过空白格子进行移动(就是俩格子交换位置)

2.可以是空白格子在起点格子四周移动,可以看成转方向。如果只用上面那种转移,也就是用起点格子自己换方向,可能没那么优秀,因为换来换去要绕一绕 。而且起点格子有可能会跑到一个离终点的地方去了,更不优。而只动空白格子可能会优秀一些 因为空白格子最优(到处都是活动格子)只用走2~4步。

然后我们发现,对于多组数据,棋盘的形状是没有改变的,所以大概可以预处理一下然后再询问。

怎么预处理呢?有一个比较实用的技巧,就是把状态当成图的节点,状态之间转移的代价当做边权,然后求从一个状态到另一个状态的最小步数就是从一个点到另一个点的最短路啦(其实本来$bfs$也和最短路有关系(强行沾边))

所以只需要处理出一些可行状态(可以将他们编号,以便进行最短路),然后用上面的两种转移关系连边:对于第一种,边权就是$1$,对于第二种,边权就是两点之间的最短路(可以$bfs$预处理,此时的最短路相当于边权为$1$)。由于边权不是全为$1$,不能用$bfs$,要写最短路算法,只要不是$floyd$,随便写哪个都可以的。

每次询问的时候,求出空白格子不经过起点格子(如果经过,起点格子位置就变啦)到起点格子四周的最短距离(可$bfs$),再从那四个状态出发(可以同时压进去的,因为答案没有叠加部分,都是一直不停更新最短距离,相当于取$min$),跑到终点格子。终点格子的四个状态都可以,取$min$就是答案。

果然吧,还是暴力好写,正解调了一个下午,考试的时候写暴力真的太划算了。

代码示例

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 using namespacestd;9 #define ll long long

10 #define INF 0x3f3f3f3f

11 #define N 35

12 intrd()13 {14 int f=1,s=0;char c=getchar();15 while(c'9'){if(c=='-') f=-1;c=getchar();}16 while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+(c^48);c=getchar();}17 return f*s;18 }19 const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};20 //下上右左

21 intn,m,q;22 intmp[N][N];23 intex,ey,sx,sy,tx,ty;24 int cnt[N][N][5];25 bool check(int xx,intyy)26 {27 if(xx<=0||xx>n||yy<=0||yy>m||mp[xx][yy]==0) return 0;28 return 1;29 }30 inttot;31 structnode{32 int x,y,stp/*广搜的时候用 存步数*/;33 };34 bool vis[N][N],mark[N*N]/*spfa的标记数组*/;35 vector >G[N*N];36 void add(int u,int v,intw)37 {38 G[u].push_back(make_pair(v,w));39 }40 int bfs(int ax,int ay,int bx,int by,int cx,intcy)41 {//a到b不经过点c的最短距离

42 if(ax==bx&&ay==by) return 0;//起点就是终点

43 memset(vis,0,sizeof(vis));44 queueQ;45 while(!Q.empty()) Q.pop();46 node s;s.x=ax,s.y=ay,s.stp=0;47 Q.push(s);48 vis[ax][ay]=1;49 while(!Q.empty())50 {51 node now=Q.front();Q.pop();52 if(now.x==bx&&now.y==by) returnnow.stp;53 for(int i=0;i<4;i++)54 {55 node nxt;56 nxt.x=now.x+dx[i],nxt.y=now.y+dy[i];57 if(!check(nxt.x,nxt.y)) continue;58 if(nxt.x==cx&&nxt.y==cy) continue;59 if(vis[nxt.x][nxt.y]) continue;60 nxt.stp=now.stp+1;61 Q.push(nxt);62 vis[nxt.x][nxt.y]=1;63 }64 }65 return INF;//不能到达

66 }67 voidInit()68 {69 //cnt存状态标号 spfa的时候是把点看成状态 用边来表示状态的转移70 //[i][j][k]是表示开始的那个点的坐标是(i,j) 空格在它的k方向

71 tot=0;72 for(int i=1;i<=n;i++)73 for(int j=1;j<=m;j++)74 for(int k=0;k<4;k++)75 if(mp[i][j]&&check(i+dx[k],j+dy[k]))76 cnt[i][j][k]=++tot;//给状态标号 没有标号的就是不可行的状态

77 for(int i=1;i<=n;i++)78 for(int j=1;j<=m;j++)79 for(int k=0;k<4;k++)80 if(cnt[i][j][k])81 {82 inttmp;83 if(k==0) tmp=1;84 if(k==1) tmp=0;85 if(k==2) tmp=3;86 if(k==3) tmp=2;87 add(cnt[i][j][k],cnt[i+dx[k]][j+dy[k]][tmp],1);88 //连单向边就可以了 后面会遍历到旁边状态连回来的89 //交换空白格子和起点格子 只需要一步

90 }91 for(int i=1;i<=n;i++)92 for(int j=1;j<=m;j++)93 for(int k=0;k<4;k++)94 for(int p=0;p<4;p++)//枚举起点格子相邻一圈的两个格子

95 if(k!=p&&cnt[i][j][k]&&cnt[i][j][p])96 add(cnt[i][j][k],cnt[i][j][p],bfs(i+dx[k],j+dy[k],i+dx[p],j+dy[p],i,j));97 //可以起点格子不动 而空白格子绕着它转(换方向)98 //如果用起点格子自己换方向 可能没那么优秀因为要绕一绕99 //而且起点格子有可能会跑到一个离终点的地方去了 更不优100 //而只动空白格子可能会优秀一些 因为空白格子最优(到处都是活动格子)只用走2~4步101

102 //经过其他格子没有任何影响 因为都是1 只是空白格子变了而已103 //而经过起点格子则会改变起点格子的坐标

104 }105 int dis[N*N];106 intspfa()107 {108 queueQ;109 while(!Q.empty()) Q.pop();110 if(sx==tx&&sy==ty) return 0;111 memset(dis,INF,sizeof(dis));112 memset(mark,0,sizeof(mark));113 for(int k=0;k<4;k++)114 {//空格先走到起点的四周 初始状态 以空格从起点四周开始

115 if(cnt[sx][sy][k])116 {117 dis[cnt[sx][sy][k]]=bfs(ex,ey,sx+dx[k],sy+dy[k],sx,sy);118 Q.push(cnt[sx][sy][k]);119 mark[cnt[sx][sy][k]]=1;120 }121 }122 while(!Q.empty())123 {124 int u=Q.front();Q.pop();125 mark[u]=0;126 for(int i=0;idis[u]+w)130 {131 dis[v]=dis[u]+w;132 if(!mark[v])133 {134 Q.push(v);135 mark[v]=1;136 }137 }138 }139 }140 //空格在哪里不用管 起点格子到了就可以141 //从空格在起点格子四周随便哪个地方的状态到空格在终点格子四周随便哪个地方的状态

142 int res=INF;143 for(int k=0;k<4;k++)144 if(cnt[tx][ty][k])145 res=min(res,dis[cnt[tx][ty][k]]);146 if(res==INF) return -1;//走不到

147 returnres;148 }149 intmain()150 {151 n=rd(),m=rd(),q=rd();152 for(int i=1;i<=n;i++)153 for(int j=1;j<=m;j++)154 mp[i][j]=rd();155 Init();156 while(q--)157 {158 ex=rd(),ey=rd(),sx=rd(),sy=rd(),tx=rd(),ty=rd();159 printf("%d\n",spfa());160 }161 return 0;162 }

Code

python华容道最短路径_NOIp2013D2T3 华容道【搜索图论-最短路】相关推荐

  1. python华容道最短路径_SSOJ1322华容道(NOIP2013)

    题目大意:在一个棋盘上,0不能做,1可以走,现在要将一个棋子移动到目标位置,移动时只能跟空格(只有一个)交换位置,至少要多少步? 题目描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一 ...

  2. python快速实现数字华容道小游戏

    华容道,中国历史地名.据<资治通鉴>注释中的说法,就是"从此道可至华容也".这里所说的华容,当然是指华容县城.华容道也就是赤壁战争中曹军逃入华容县界后向华容县城逃跑的路 ...

  3. 利用Python解决最短路径问题

    利用Python解决最短路径问题 题意 运行限制 解题思路 代码 法一(基于最短路径长度递增): 法二(基于图论中的最短路径算法): 推荐练习 题意 一图由 2021 个结点组成,依次编号 1 至 2 ...

  4. python最短路径,如何用python实现最短路径

    用python实现最短路径的方法:1.迪杰斯特拉算法:声明一个数组dis来保存源点到各个顶点的最短距离:2.弗洛伊德算法:在有向图中求解点与点之间最短路径:3.SPFA算法:用数组dis记录每个结点的 ...

  5. python 利用 whoosh 搭建轻量级搜索

      本文将简单介绍Python中的一个轻量级搜索工具Whoosh,并给出相应的使用示例代码. Whoosh简介   Whoosh由Matt Chaput创建,它一开始是一个为Houdini 3D动画软 ...

  6. 在哪里能收到python实例代码-python仿evething的文件搜索器实例代码

    今天看到everything搜索速度秒杀windows自带的文件管理器,所以特地模仿everything实现了文件搜索以及打开对应文件的功能,首先来一张搜索对比图. 这是evething搜索效果: 这 ...

  7. python爬虫代码实例-Python爬虫爬取百度搜索内容代码实例

    这篇文章主要介绍了Python爬虫爬取百度搜索内容代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 搜索引擎用的很频繁,现在利用Python爬 ...

  8. getprofile()获取不到路径_做一款RPG游戏,几乎都会用到的Python坐标最短路径计算...

    角色扮演游戏(Role-playing game),简称为RPG,是游戏类型的一种.在游戏中,玩家负责扮演这个角色在一个写实或虚构世界中活动. 玩家负责扮演一个或多个角色,并在一个结构化规则下通过一些 ...

  9. 利用python从网页查找数据_利用Python模拟淘宝的搜索过程并对数据进行可视化分析...

    数据挖掘入门与实战 公众号: datadw 本文讲述如何利用Python模拟淘宝的搜索过程并对搜索结果进行初步的数据可视化分析. 搜索过程的模拟:淘宝的搜索页面有两种形式, 一种形式是, 2019/2 ...

最新文章

  1. 阿里云系列——7.阿里云IIS系列详解(过程+通用+最新)
  2. oracle 数据库 触发器 trigger 语法
  3. python文件和目录操作方法
  4. 使用Scalatra创建Scala WEB工程
  5. 【编译原理】学习LUA
  6. STM32利用库函数驱动OLED
  7. Hibernate的发展和特点以及Hibernate的工作原理简介
  8. 统一沟通-技巧-9-Lync 2010-Outlook 2010-自动配置-1-IT人员
  9. Dynamics CRM2013 6.1.1.1143版本号插件注冊器的一个bug
  10. luoguP3281 [SCOI2013]数数
  11. SAP ABAP Loop…Assigning与Loop…Into的比较
  12. 2021-02-02美赛前MATLAB的学习笔记(机器学习(分类、聚类、深度学习))
  13. pytorch中的collate_fn 是什么作用
  14. 朱清时看何谓大学生之“大”
  15. Python-量化投资(二)
  16. linux移动硬盘直接拔掉,安全弹出后就拔掉移动硬盘,真的安全吗?
  17. 文献日志:EMNLP2020-自适应性语言普适分析器
  18. 问题解决:VScode高CPU占有率 Microsoft.VSCode.CPP.Extension.darwin
  19. jQuery 清除div内容
  20. git安装及github配置

热门文章

  1. Spring官方都说废掉GuavaCache用Caffeine,你还不换?
  2. Spring Cloud Alibaba到底坑不坑?反正是解放了部分使用的繁琐!
  3. 表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
  4. EasyPoi 的样式使用及其自定义
  5. 架构设计:分布式结构下,服务部署发布
  6. Java描述设计模式(06):建造者模式
  7. 关于hexo更新到GitHub后博客内容未变问题
  8. 蚌埠学院官网综合新闻条目抓取
  9. TypeError: cannot perform reduce with flexible type
  10. 创建Podfile,添加类库,中途添加库指令