openjudge_2.5基本算法之搜索_1804:小游戏

news2024/11/28 8:33:10

题目

1804:小游戏
总时间限制: 1000ms 内存限制: 65536kB
描述
一天早上,你起床的时候想:“我编程序这么牛,为什么不能靠这个赚点小钱呢?”因此你决定编写一个小游戏。
游戏在一个分割成w * h个正方格子的矩形板上进行。如图所示,每个正方格子上可以有一张游戏卡片,当然也可以没有。
当下面的情况满足时,我们认为两个游戏卡片之间有一条路径相连:路径只包含水平或者竖直的直线段。路径不能穿过别的游戏卡片。但是允许路径临时的离开矩形板。下面是一个例子:
在这里插入图片描述
这里在 (1, 3)和 (4, 4)处的游戏卡片是可以相连的。而在 (2, 3) 和 (3, 4) 处的游戏卡是不相连的,因为连接他们的每条路径都必须要穿过别的游戏卡片。
你现在要在小游戏里面判断是否存在一条满足题意的路径能连接给定的两个游戏卡片。
输入
输入包括多组数据。一个矩形板对应一组数据。每组数据包括的第一行包括两个整数w和h (1 <= w, h <= 75),分别表示矩形板的宽度和长度。下面的h行,每行包括w个字符,表示矩形板上的游戏卡片分布情况。使用‘X’表示这个地方有一个游戏卡片;使用空格表示这个地方没有游戏卡片。
之后的若干行上每行上包括4个整数x1, y1, x2, y2 (1 <= x1, x2 <= w, 1 <= y1, y2 <= h)。给出两个卡片在矩形板上的位置(注意:矩形板左上角的坐标是(1, 1))。输入保证这两个游戏卡片所处的位置是不相同的。如果一行上有4个0,表示这组测试数据的结束。
如果一行上给出w = h = 0,那么表示所有的输入结束了。
输出
对每一个矩形板,输出一行“Board #n:”,这里n是输入数据的编号。然后对每一组需要测试的游戏卡片输出一行。这一行的开头是“Pair m: ”,这里m是测试卡片的编号(对每个矩形板,编号都从1开始)。接下来,如果可以相连,找到连接这两个卡片的所有路径中包括线段数最少的路径,输出“k segments.”,这里k是找到的最优路径中包括的线段的数目;如果不能相连,输出“impossible.”。
每组数据之后输出一个空行。
样例输入
5 4
XXXXX
X X
XXX X
XXX
2 3 5 3
1 3 4 4
2 3 3 4
0 0 0 0
0 0
样例输出
Board #1:
Pair 1: 4 segments.
Pair 2: 3 segments.
Pair 3: impossible.

理解

  • 地图字符间没有空格,可以用c=cin.get()提取字符。注意须得用cin.get()消融换行符。
  • 除了起点和终点外的卡片不能走。可以走地图外一圈。地图只有1到5列,可以走0和6列。
  • 宽搜可以求出发点到目的地的步数,可惜问的是出发点到目的地线路变向次数,就是线段数。方向不一样要用深搜。
    宽搜找步数,线路有区别用深搜 5. 深搜,标记并找到通往终点的线路,变向就增加。回溯找到最短的线路。格子来的方向和周围某邻格子移动方向一致,不用转向,否则转向。 6. List item
  • 深搜剪枝非常重要。超过已有更佳答案的停止搜索。

回溯深搜代码

#include <bits/stdc++.h>
using namespace std;
const int inf=99999;
struct point{int x,y;};//坐标和到达步数
int r,c,//行列
ans,//最少步数
z1,z2,//几组地图,每组几组数据
x2,y2,x3,y3,//出发到达坐标
d[5][2]={{0,0},{0,1},{1,0},{0,-1},{-1,0}};//一个格子往周围四个方向移动
bool k[80][80],k2[80][80],k3[80][80];//表示能不能走,也标记走过没
char cx,cc[80][80];//地图每格字符
void view(){
cout<<“显示”<<endl;
for(int i=0;i<=r+1;i++){
for(int j=0;j<=c+1;j++){
if(ix2&&jy2)cout<<“s”;
else if(ix3&&jy3)cout<<“e”;
else cout<<" “;
cout<<cc[i][j]<<k3[i][j]<<”\t";
}
cout<<endl;
}

}
void go(point p,int dx,int he){//递归,该点移动方向,到达目的地最少线段数
if(p.xx3&&p.yy3){
for(int i=0;i<=r+1;i++)for(int j=0;j<=c+1;j++)k3[i][j]=k[i][j];
ans=min(ans,he);return;//到达目的地,该次递归结束
}
if(he>=ans)return;//剪枝,如果线段树超过已有最少线段数,就停止递归
int x,y;
for(int i=1;i<=4;i++){
x=p.x+d[i][0],y=p.y+d[i][1];//四个方向移动后坐标
if((!k[x][y]||xx3&&yy3)&&x>=0&&x<=r+1&&y>=0&&y<=c+1){//新坐标在地图里,不是卡片或者到达目标
k[x][y]=1;//标记,下次不走了
if(idx||dx0)go(point{x,y},i,he);//没有转向,到达这里的线段数不变
else go(point{x,y},i,he+1);//转向了,线段数增加
k[x][y]=0;//回溯,撤销上一步
}
}
}
int main(){
freopen(“data.cpp”,“r”,stdin);
while(cin>>c>>r&&(r||c)){//列行,非零循环
cin.get();//消融上一行换行符
memset(k2,0,sizeof(k2));//标记卡片位置
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
cx=cin.get();cc[i][j]=cx;
if(cx==‘X’)k2[i][j]=1;//不能走
else if(cx==’ ')k2[i][j]=0; //能走
}
cin.get();//消融上一行换行符
}
cout<<“Board #”<<++z1<<“:”<<endl;
z2=1;
while(cin>>y2>>x2>>y3>>x3&&(x2||y2||x3||y3)){
for(int i=0;i<=r+1;i++)for(int j=0;j<=c+1;j++)k[i][j]=k2[i][j];//恢复地图
ans=inf;//从最大中找最少
go(point{x2,y2},0,1);//从起点回溯递归
cout<<“Pair “<<z2++<<”:”;
if(ans<inf)cout<<" “<<ans<<” segments.\n";
else cout<<" impossible.\n";
view();
}
cout<<endl;
}
return 0;
}

记忆化递归

  • 存储每个格子四个方向的最佳值,不是零就直接返回,否则就需要计算,变向就是下个格子值+1,不变就不加。

  • 注意跳出递归条件。

  • 在这里插入图片描述

  • 递归返回值就是记忆化递归,不返回就是深搜。
    在这里插入图片描述

记忆化递归代码

#include <bits/stdc++.h>
using namespace std;
//typedef inf 0x7f7f7f7f;别名
#define inf 99 //极大值,表示到不了目的地
int r,c,//行列
ans,//到达目的地最少线条数
z1,z2,//几组地图,每组几组数据
x,y,//宽搜当前坐标
x2,y2,x3,y3,//出发到达坐标
d[5][2]={{0,0},{0,-1},{-1,0},{0,1},{1,0}},//移动方向
dn[80][80][5];//记住每个格子五个方向的到达线条数
char cx,cc[80][80];//地图便于纠误
bool k[80][80];//标记卡牌位置
void view(int x2,int y2,int x3,int y3){//标明出发结束位置
for(int i=0;i<=r+1;i++){//可以走外围一圈
for(int j=0;j<=c+1;j++){
if(ix2&&jy2)cout<<“S”;//标识出发
else if(ix3&&jy3)cout<<“E”;//目的地
else cout<<" “;
cout<<cc[i][j]<<”:“<<setw(2)<<dn[i][j][1]<<”,“<<setw(2)<<dn[i][j][2]<<”,“<<setw(2)<<dn[i][j][3]<<”,“<<setw(2)<<dn[i][j][4]<<” “;
}cout<<endl;
}
cout<<endl;
}
int go(int xx,int yx,int dx){//往同一方向走一格,四个方向得递归该邻格,得到本格和该邻格的线条数
if(dn[xx][yx][dx])return dn[xx][yx][dx];//已经算过了就不再算了
if(xxx3&&yxy3){//到达目标位置,线条数是0
for(int i=1;i<=4;i++)dn[xx][yx][i]=1;
return 1;
}
if(k[xx][yx]){//有卡片是无穷大
for(int i=1;i<=4;i++)dn[xx][yx][i]=inf;
return inf;
}
int x,y;
dn[xx][yx][dx]=inf;//找最小值,先赋最大值
x=xx+d[dx][0],y=yx+d[dx][1];//同一方向跨一格
//!!!该步已经在卡片上了,貌似不能不访问卡片
if(x>=0&&x<=r+1&&y>=0&&y<=c+1)//该格子在地图里
for(int i=1;i<=4;i++){//四个方向
dn[x][y][i]=go(x,y,i);//继续计算该邻格的线条数
if(idx)dn[xx][yx][dx]=min(dn[xx][yx][dx],dn[x][y][i]);//同向不变
else dn[xx][yx][dx]=min(dn[xx][yx][dx],dn[x][y][i]+1);//异向增1
}
return dn[xx][yx][dx];//要循环四次,找最小值,不能直接返回
}
int main(){
freopen(“data.cpp”,“r”,stdin);
while(cin>>c>>r&&(r||c)){//列行,非零循环
cin.get();//前一行输入后回车
memset(k,0,sizeof(k));//地图表示卡片
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
cx=cin.get();cc[i][j]=cx;
if(cx
’X’)k[i][j]=1;//不能走
}
cin.get();//消除该行结束符
}
cout<<“Board #”<<++z1<<”:“<<endl;
z2=1;
while(cin>>y2>>x2>>y3>>x3&&(x2>0||y2>0||x3>0||y3>0)){//一个地图多组数据
ans=inf;
memset(dn,0,sizeof(dn));//所有格子都没算过
view(x2,y2,x3,y3);
for(int i=1;i<=4;i++){//往四个方向出发
dn[x2][y2][i]=inf;//找最小值,所以是最大值
x=x2+d[i][0],y=y2+d[i][1];//四个方向邻格
for(int j=1;j<=4;j++){//算邻格四方向
dn[x][y][j]=go(x,y,j);//递归计算
if(i==j)dn[x2][y2][i]=min(dn[x2][y2][i],dn[x][y][j]);//同向不变
else dn[x2][y2][i]=min(dn[x2][y2][i],dn[x][y][j]+1);//异向增1
}
ans=min(ans,dn[x2][y2][i]);//找最小值
}
view(x2,y2,x3,y3);
cout<<“Pair “<<z2++<<”:”;
if(ans<inf)cout<<” “<<ans+1<<” segments.\n";
else cout<<" impossible.\n";
}
cout<<endl;
}
return 0;
}

小结

先宽搜,再深搜,再记忆化递归。

  • 没读透题,不够认真,错以为要求步数。
  • 深搜是不返回值的递归。注意剪枝
  • 记忆化递归要返回值。注意要有返回值。
  • 把演示数据表现出来有助于理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1603632.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用自定义Promptbooks优化您的安全工作流程

在当今的数字化时代&#xff0c;安全工作流程的优化变得前所未有的重要。安全团队需要快速、有效地响应安全事件&#xff0c;以保护组织的数据和资产。Microsoft Copilot for Security提供了一种强大的工具——自定义Promptbooks&#xff0c;它可以帮助安全专家通过自动化和定制…

【shell】利用k9s和config文件进入k8s集群脚本

1、需要自行安装k9s 2、config文件放在home的.kube隐藏文件夹下 #!/bin/bash# define log & color readonly FG_GREY"30" #灰色 readonly FG_RED"31" readonly FG_GREEN"32" readonly FG_YELLOW"33" readonly FG_BLU…

element-plus中的图标和文字水平对齐

<span><el-icon size"14px"><Delete /></el-icon> <span>删除</span> </span>解决方法&#xff1a;加上vertical-align: middle样式就可以了 <span><el-icon size"14px" style"vertical-align: …

搜维尔科技:【工业仿真】煤矿安全知识基础学习VR系统

产品概述 煤矿安全知识基础学习VR系统 系统内容&#xff1a; 煤矿安全知识基础学习VR系统内容包括&#xff1a;下井流程&#xff08;正确乘坐罐笼、班前会、井下行走注意事项、工作服穿戴、入井检身及人员清点、下井前准备工作、提升运输安全&#xff09;&#xff1b;运煤流程…

Web前端 Javascript笔记5

1、事件类型 ①、HTML事件 事件说明load当页面完全加载后在window上面触发&#xff0c;或当框架集加载完毕后在框架集上触发&#xff1b;unload当页面完全卸载后在window上面触发&#xff0c;或当框架集卸载后在框架集上触发&#xff1b;select当用户选择文本框&#xff08;i…

如何在原生项目中集成flutter

两个前提条件&#xff1a; 从flutter v1.17版本开始&#xff0c;flutter module仅支持AndroidX的应用在release模式下flutter仅支持一下架构&#xff1a;x84_64、armeabi-v7a、arm6f4-v8a,不支持mips和x86;所以引入flutter前需要在app/build.gradle下配置flutter支持的架构 a…

springSecurity用户认证和授权

一&#xff0c;框架介绍 Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架&#xff0c;提供了一套 Web 应用安全性的完整解决方案。一般来说&#xff0c;Web 应用的安全性包括用户认证&#xff08;Authentication&#xff09;和用户授权&am…

EelasticSearch的docker安装-----》es客户端使用!!!

1.Docker安装 docker run -d --name es7 -e ES_JAVA_POTS"-Xms256m -Xmx256m" -e "discovery.typesingle-node" -v /opt/es7/data/:/usr/share/elasticsearch/data -p 9200:9200 -p 9300:9300 elasticsearch:7.14.02.客户端UI工具&#xff0c;Edge浏览器…

量子密钥分发系统设计与实现(一):系统基本架构讨论

经过一段时间讨论&#xff0c;我们了解到量子密钥分发设备是当前量子保密通信系统的基础。从本文开始&#xff0c;我将开启量子密钥分发系统设计与实现系列&#xff0c;详细讨论量子密钥分发设备如何从0到1的搭建。 1.QKD系统总体讨论 QKD系统的核心功能就是为通信双方提供理论…

Unity之XR Interaction Toolkit如何在VR中实现渐变黑屏效果

前言 做VR的时候,有时会有跳转场景,切换位置,切换环境,切换进度等等需求,此时相机的画面如果不切换个黑屏,总会感觉很突兀。刚好Unity的XR Interaction Toolkit插件在2.5.x版本,出了一个TunnelingVignette的效果,我们今天就来分析一下他是如何使用的,然后我们自己再来…

ABAP - 三代增强 BADI

SAP ERP提供了大量的标准功能&#xff0c;但是用户的需求是多种多样的&#xff0c;如何使SAP的标准功能适应用户的需求就变得非常重要&#xff0c;SAP Enhancement技术允许我们对SAP的标准功能进行扩展&#xff0c;以满足用户的个性化需求&#xff1b;SAP保证所有的BADI向上兼容…

Stable Diffusion之Ubuntu下部署

1、安装conda环境 conda create -n webui python3.10.6 2、激活环境 每次使用都要激活 conda activate webui 注意开始位置的变换 关闭环境 conda deactivate webui 3、离线下载SD 代码 https://github.com/AUTOMATIC1111/stable-diffusion-webui https://github.com/Stabilit…

小红书app缓存清除

1.背景 小伙伴们&#xff0c;手机app运行产生的缓存在不断侵占着我们的收集的内存&#xff0c;运行个半年发现内存不足20%。其实很多情况我们通过各个手机自带的缓存清除功能&#xff0c;就可以把app运行过程中产生的内存清除掉&#xff0c;节省我们不少的空间。想一想手机上a…

【FreeRTOS】使用CubeMX快速移植FreeRTOS工程到蓝桥杯开发板(STM32G431RBT6)

使用CubeMX快速创建FreeRTOS工程到蓝桥杯开发板&#xff08;STM32G431RBT6&#xff09; CubeMX配置CubeMX基础工程的配置☆FreeRTOS相关配置FreeRTOS配置选项卡的解释 软件工程架构与程序设计小综合&#xff1a;任务的创建删除、挂起与恢复设计cubexMX配置创建任务软件程序设计…

前端服务请求跨域被拦截,Java后端Springboot服务解决办法

跨域问题 跨域前端遇到的问题&#xff1a; Access to XMLHttpRequest at ‘http://www.xxx.xxxx/api/x/d/xc’ from origin ‘http://127.0.0.1:3000’ has been blocked by cors policy: No ‘Access-Contorl-Allow-Origin’ header is present on the requested resource. …

8.Jetson AGX Orin Ubuntu20.04 gRPC编译安装

Jetson AGX Orin Ubuntu20.04 gRPC编译安装 一、CMake版本检查 grpc编译cmake要求最低版本为3.15。首先&#xff0c;cmake -version 查看当前cmake版本&#xff0c;如果低于3.15&#xff0c;按照以下步骤进行安装。 1.1 卸载已经安装的旧版的CMake sudo apt-get autoremove…

Golang插件系统实现

插件可以在解耦的基础上灵活扩展应用功能&#xff0c;本文介绍了如何基于Golang标准库实现插件功能&#xff0c;帮助我们构建更灵活可扩展的应用。原文: Plugins with Go 什么是插件 简单来说&#xff0c;插件就是可以被其他软件加载的软件&#xff0c;通常用于扩展应用程序的功…

嵌入式学习56-ARM5(linux驱动启动程序)

知识零碎&#xff1a; bootm&#xff1a; 启动内核同时给内核传参 …

VAR:自回归家族文生图新SOTA,ImageNet上超越Diffusion与DiTs

一、背景&#xff1a; 在人工智能领域&#xff0c;尤其是计算机视觉和自然语言处理中&#xff0c;自回归&#xff08;AR&#xff09;大型模型&#xff08;如GPT系列&#xff09;因其强大的生成能力和在多种任务上的通用性而受到广泛关注。这些模型通过自监督学习策略&#xff0…

Android 性能优化(七):APK安装包体积优化

包体积优化重要性 移动 App 特别关注投放转化率指标&#xff0c;而 App 包体积是影响用户新增的重要因素&#xff0c;而 App 的包体积又是影响投放转化率的重要因素。 Google 2016 年公布的研究报告显示&#xff0c;包体积每上升 6MB 就会带来下载转化率降低 1%&#xff0c; …