openjudge_2.5基本算法之搜索_7221:拯救公主

题目

7221:拯救公主
总时间限制: 1000ms 内存限制: 65536kB
描述
多灾多难的公主又被大魔王抓走啦!国王派遣了第一勇士阿福去拯救她。

身为超级厉害的术士,同时也是阿福的好伙伴,你决定祝他一臂之力。你为阿福提供了一张大魔王根据地的地图,上面标记了阿福和公主所在的位置,以及一些不能够踏入的禁区。你还贴心地为阿福制造了一些传送门,通过一个传送门可以瞬间转移到任意一个传送门,当然阿福也可以选择不通过传送门瞬移。传送门的位置也被标记在了地图上。此外,你还查探到公主所在的地方被设下了结界,需要集齐K种宝石才能打开。当然,你在地图上也标记出了不同宝石所在的位置。你希望阿福能够带着公主早日凯旋。于是在阿福出发之前,你还需要为阿福计算出他最快救出公主的时间。地图用一个R×C的字符矩阵来表示。字符S表示阿福所在的位置,字符E表示公主所在的位置,字符#表示不能踏入的禁区,字符$表示传送门,字符.表示该位置安全,数字字符0至4表示了宝石的类型。阿福每次可以从当前的位置走到他上下左右四个方向上的任意一个位置,但不能走出地图边界。阿福每走一步需要花费1个单位时间,从一个传送门到达另一个传送门不需要花费时间。当阿福走到宝石所在的位置时,就视为得到了该宝石,不需要花费额外时间。

输入
第一行是一个正整数T(1 <= T <= 10),表示一共有T组数据。
每一组数据的第一行包含了三个用空格分开的正整数R、C(2 <= R, C <= 200)和K,表示地图是一个R×C的矩阵,而阿福需要集齐K种宝石才能够打开拘禁公主的结界。
接下来的R行描述了地图的具体内容,每一行包含了C个字符。字符含义如题目描述中所述。保证有且仅有一个S和E。$的数量不超过10个。宝石的类型在数字0至4范围内,即不会超过5种宝石。
输出
对于每一组数据,输出阿福救出公主所花费的最少单位时间。若阿福无法救出公主,则输出“oop!”(只输出引号里面的内容,不输出引号)。每组数据的输出结果占一行。
样例输入
1
7 8 2

…S…#0.
.##…1…
.0#…
…1#…
…##E…
…1…
样例输出
11

理解

1.宽搜可以找到最短距离
2.凑齐宝石可以打开结界
不能只标记坐标,还要标记拥有宝石种类状况
没有宝石时到达的标记
有一种宝石时标记
两种三种都要标记
3.用二进制对应数字表示不同状态
如共四个宝贝
无宝石 0000 0
第0种 0001 1
第1种 0010 2
0、1 0011 3
第3种 0100 4
0、3 0101 5
以此类推。
不仅标记那种状态
还要记住该种状态到达所用时间
当然可以合到一起,所用时间0标记没来过,非零就是来过
4.四个宝贝,最大值是pow(2,0)+pow(2,1)+pow(2,2)+pow(2,3)=15。
就是状态是15就表示宝石凑齐。
5.传送门,不耗时,只要不是门自己就可以去。当然要判断该状态下去过没。
6.题目有问题,根据不同地图的测评,发现ac代码要求S点只能出发一次,再不能借过。
其实从题意里看不到这个概念,持有不同宝石时(不同状态时),是可以结果的。
本代码就没有强调这点,也还AC了。这里不解!!!
7.题目几个宝石就是几个,不能因为地图中出现的宝石收干扰
8.到达某个点后,不仅当前状态要增加,别的状态也得传递。所以最好还是拷贝节点。
但是不能拷贝各状态是否走过的标记,会超时
9.从某点出发,能不能到周边点,不是看目的地状态,而是出发点的状态
10.x!=dx||y!=dy行列有一个不同就非同点。

代码

#include <bits/stdc++.h>
using namespace std;
struct point{
char c;//地图字符
int x,y,//节点坐标
t,//步数
td;//状态,用数字表示拥有哪些宝石
bool k[5],//有哪些宝石
kt[31];//拥有哪些宝石时是否走过,(没用上,用不成,会超时)
point(){
memset(k,0,sizeof(k));
memset(kt,0,sizeof(kt));
t=0;td=0;
}
point(char cx,int xx,int yx){
memset(k,0,sizeof(k));
memset(kt,0,sizeof(kt));
c=cx,x=xx,y=yx;t=0;td=0;
}
}p[201][201],p1,p2,p3,door[15];
int t,ans,h,w,
km,//宝石种类数量
dm,//传送门数量
x,y,
md,//最大状态数
d[4][2]={0,-1,-1,0,0,1,1,0};
char c;
bool k[201][201][31];//标记每个点持有不同宝石时是否走过。
void view(point px){
cout<<px.x<<“\t”<<px.y<<endl;
cout<<“列:\t”;
for(int j=1;j<=w;j++)cout<<setw(8)<<j<<“\t”;cout<<endl;
for(int i=1;i<=h;i++){
cout<<i<<“行:\t”;
for(int j=1;j<=w;j++){
cout<<p[i][j].c<<“,”<<p[i][j].t<<“:”;
for(int x=0;x<=md;x++)cout<<setw(2)<<p[i][j].kt[x];
cout<<“\t”;
}cout<<endl;
}
}
bool ok(point p){//判定宝石带全否
for(int i=0;i<km;i++)if(!p.k[i])return 0;
return 1;
}
int main(){
freopen(“data.cpp”,“r”,stdin);
cin>>t;
while(t–){//多组数据
cin>>h>>w>>km;
md=0;
for(int i=0;i<km;i++)md+=pow(2,i);
memset(k,0,sizeof(k));//初始化
queue q;
ans=h * w;dm=0;
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++){
cin>>c;
p[i][j]=point{c,i,j};//初始化地图每个节点
if(c==‘S’){
q.push(p[i][j]);
p[i][j].kt[0]=1;//没宝石时标记走过(本题中没有用到)
}else if(c==’ $ ‘)door[dm++]=p[i][j];
}
while(!q.empty()){
p1=q.front();q.pop();
if(p1.c==‘E’&&ok(p1)){
ans=p1.t;break;
}
view(p1);
for(int i=0;i<4;i++){
x=p1.x+d[i][0],y=p1.y+d[i][1];c=p[x][y].c;
if(x<1||x>h||y<1||y>w||c==’#‘)continue;
p2=p1;
p2.x=x,p2.y=y,p2.t=p1.t+1;p2.c=c;
if(c>=‘0’&&c<km+‘0’){//多了个宝石
if(!p2.k[c-‘0’]){
p2.k[c-‘0’]=1;
p2.td+=pow(2,c-‘0’);//调整状态
}
}
//if(p[x][y].kt[td])continue;
//p2.kt[td]=1;//该两句没有用到,用了会反馈超时
if(k[x][y][p2.td])continue;//如果已经走过,不再走
k[x][y][p2.td]=1;//标记此节点此状态已走过。
p[x][y]=p2;
if(c==’$')
for(int j=0;j<dm;j++){
int dx=door[j].x,dy=door[j].y;
if(!(dx= =x&&dy= =y)){//只要不是门本身就传送
p3=p2;
p3.x=dx,p3.y=dy,p3.c=door[j].c;
p[dx][dy]=door[j]=p3;
q.push(door[j]);//传送门出发
}
}
q.push(p2);//本节点出发
}
}
if(ans==w * h)cout<<“oop!”<<endl;
else cout<<ans<<endl;
}
return 0;
}

小结

还是宽搜,找最短距离
因为宝石可以继承,所以到达点先继承出发点,再修改成本节点。
用持有宝石的品种数——多状态标记是否走过某个节点。
而这个多状态k[201][201][31]必须是独立的数组,放在节点里会超时(这个不理解,哪位仁兄给个指点)!

更美代码

#include <bits/stdc++.h>
using namespace std;
struct point{
char c;
int x,y,
td, //有几种宝石的状态,移动时要传承
t;//不同状态到达该位置所用时间
bool k[5];//拥有哪些宝石,
point(){
t=td=0;
memset(k,0,sizeof(k));
}
point(char cx,int xx,int yx){
c=cx,x=xx,y=yx;
t=td=0;
memset(k,0,sizeof(k));
}
}p[201][201],p1,p2,p3,door[15];
bool k[201][201][31];
int n,//组数
h,w,//宽高
m,//宝石种类数
md,//最大状态
x,y,//新坐标
dm,//传送门数
ans,//到达最短时间
d[4][2]={{0,-1},{0,1},{-1,0},{1,0}};
char c;
void view(point px){
cout<<px.x<<“\t”<<px.y<<endl;
cout<<“列:\t”;
for(int j=1;j<=w;j++){
cout<<setw(4)<<j<<“:”;
for(int i=0;i<=md;i++)cout<<i;
cout<<“\t”;
}
cout<<endl;
for(int i=1;i<=h;i++){
cout<<i<<“行:\t”;
for(int j=1;j<=w;j++){
cout<<p[i][j].c<<“,”<<setw(2)<<p[i][j].t<<“:”;
for(int x=0;x<=md;x++)cout<<k[i][j][x];
cout<<“\t”;
}cout<<endl;
}
}
bool ok(point p){//少一个宝石就救不了公主
for(int i=0;i<m;i++)if(!p.k[i])return 0;
return 1;
}
int main(){
//freopen(“data.cpp”,“r”,stdin);
cin>>n;
while(n–){
queue q;//多组数据,需要初始化
cin>>h>>w>>m;
md=0;for(int i=0;i<m;i++)md+=pow(2,i);
dm=0;//传送门
memset(k,0,sizeof(k));
for(int i=1;i<=h;i++)
for(int j=1;j<=w;j++){
cin>>c;
p[i][j]=point{c,i,j};
if(c==‘S’){
//但是一传承,都不能走了。错误
k[i][j][0]=1;//没宝石时已经走过了
q.push(p[i][j]);
}else if(c==’ $ ‘)door[dm++]=p[i][j];//存传送门数组中
}
//view(p[1][1]);
ans=h * w;//有不是h*w的答案,就是正确结果
while(!q.empty()){
p1=q.front();q.pop();//出发点
//cout<<“出发”<<p1.x<<“\t”<<p1.y<<endl;
if(p1.c==‘E’&&ok(p1)){
ans=p1.t;
break;
}
for(int i=0;i<4;i++){
x=p1.x+d[i][0],y=p1.y+d[i][1];//到达点
c=p[x][y].c;
if(x<1||x>h||y<1||y>w||c==’#‘)continue;
p2=p1;//继承出发点
p2.c=c,p2.x=x,p2.y=y;
p2.t++;//增加本状态时间
if(c>=‘0’&&c<m+‘0’&&!p2.k[c-‘0’]){//要多宝石,状态要变
p2.k[c-‘0’]=1;
p2.td+=pow(2,c-‘0’);//持有宝石的状态发生变化
}
if(k[x][y][p2.td])continue;//防止重复访问。状态是继承的
k[x][y][p2.td]=1;//状态时继承的状态
//cout<<“到达普通点”<<x<<“\t”<<y<<endl;
p[x][y]=p2;//继承出发点
//view(p2);
q.push(p2);//先解决传送门出发点,再传送
if(c==’ $ '){
//cout<<“到达传送门”<<x<<“\t”<<y<<endl;
for(int j=0;j<dm;j++){
int dx=door[j].x,dy=door[j].y;
if((x!=dx||y!=dy)){//不是同个门,且未去过
//另一门继承出发点的状态
p3=p2;
p3.x=dx,p3.y=dy,p3.c=door[j].c;
if(k[dx][dy][p3.td])continue;//同样判定状态,状态是继承的
k[dx][dy][p3.td]=1;
door[j]=p[dx][dy]=p3;
//cout<<“开始传送”<<dx<<“\t”<<dy<<endl;
//view(p3);
q.push(p3);
}
}
}
}
}
if(ans==h * w)cout<<“oop!\n”;
else cout<<ans<<endl;
}
return 0;
}

新代码理解

传送门当然也要判断状态时访问过没,状态是继承的
在宽搜对面的传送门前,先宽搜本传送门。
出发点标记走过是应该的。

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

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

相关文章

如何完美解决升级 IntelliJ IDEA 最新版之后遇到 Git 记住密码功能失效的问题

&#x1f6e0;️ 如何完美解决升级 IntelliJ IDEA 最新版之后遇到 Git 记住密码功能失效的问题 摘要 在这篇文章中&#xff0c;我们将详细探讨如何解决在升级到 IntelliJ IDEA 最新版&#xff08;2024.1.3 Ultimate Edition&#xff09;后遇到的 Git 记住密码功能失效的问题。…

FPGA - Verilog题目: 非整数倍数据位宽转换24to128

题目描述&#xff1a; 实现数据位宽转换电路&#xff0c;实现24bit数据输入转换为128bit数据输出。其中&#xff0c;先到的数据应置于输出的高bit位。 电路的接口如下图所示。valid_in用来指示数据输入data_in的有效性&#xff0c;valid_out用来指示数据输出data_out的有效性…

zabbix老版本3.0.14迁移

由于之前zabbix版本过老&#xff0c;一直未能升级&#xff0c;现在一台老的服务器需要迁移&#xff0c;服务器较老&#xff0c;就不更新&#xff0c;先迁移数据&#xff0c; 下载地址&#xff1a; Zabbix Official Repository http://repo.zabbix.com/zabbix/3.0/rhel/7/x86…

数据结构之线性表(4)

前面我们了解到线性表中的顺序表、链表等结构&#xff0c;今天我们探讨新的一种线性表——栈。 那么我们开始栈的探讨之旅吧。 1.栈的基本概念 1.1栈&#xff08;Stack&#xff09;&#xff1a; 是只允许在一端进行插入或删除的线性表。首先栈是一种线性表&#xff0c;但限定…

从零开始!如何安装和配置Jupyter Notebook

目录 一、Jupyter Notebook简介 二、Jupyter Notebook的安装步骤 1. 安装Python 2. 安装Jupyter Notebook 三、Jupyter Notebook的配置 1. 配置Jupyter Notebook的工作目录 2. 设置密码访问 3. 设置SSL安全连接 四、Jupyter Notebook的基本操作 1. 创建和运行Noteboo…

对象和引用类型的赋值都是通过引用传递的方式进行的,这意味着变量实际上存储的是对象的引用,而不是对象本身的副本

这篇博客我主要想解释一下这句话&#xff1a;对象和引用类型的赋值都是通过引用传递的方式进行的&#xff0c;这意味着变量实际上存储的是对象的引用&#xff0c;而不是对象本身的副本。 其实这段话早在学习JS的时候就接触过&#xff0c;只是被我丢进了“记忆垃圾桶”&#xf…

面试专区|【32道Python面向对象高频题整理(附答案背诵版)】

Python中的元类( metaclass )&#xff1f; 元类&#xff08;metaclass&#xff09;在Python中是一个相对高级且深奥的概念。简单来说&#xff0c;元类是创建类的类。在Python中&#xff0c;一切都是对象&#xff0c;类也不例外。当我们定义一个类时&#xff0c;Python会在内存…

数据仓库之离线数仓

离线数据仓库&#xff08;Offline Data Warehouse&#xff09;是一种以批处理方式为主的数据仓库系统&#xff0c;旨在收集、存储和分析大量历史数据。离线数据仓库通常用于定期&#xff08;如每日、每周、每月&#xff09;更新数据&#xff0c;以支持各种业务分析、报表生成和…

[大模型]Llama-3-8B-Instruct FastApi 部署调用

环境准备 在 Autodl 平台中租赁一个 3090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch-->2.1.0-->3.10(ubuntu22.04)-->12.1。 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行演示。 pip 换源…

C语言杂谈:结构体内存对齐

#include<stdio.h> struct S1 {char c1;int i;char c2; }; struct S2 {char c1;char c2;int i; }; int main() {printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));return 0; } 看上面的代码&#xff0c;我们想想应该会输出什么…

【MySQL】E-R图-关系数据模型-3NF--精讲+练习(巨全面)

一.知识储备 E-R图 E-R图&#xff0c;即实体-关系图&#xff08;Entity-Relationship Diagram&#xff09;&#xff0c;是数据库建模的一种工具&#xff0c;用于表示实体类型、属性以及它们之间的关系。 在E-R图中&#xff0c;实体用矩形表示&#xff0c;属性用椭圆表示&…

【最新鸿蒙应用开发】——关于鸿蒙MVVM模式的理解

MVVM模式 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种软件设计模式&#xff0c;主要用于分离应用程序的用户界面&#xff08;UI&#xff09;和业务逻辑。这种模式可以帮助开发者更高效地开发和管理复杂的用户界面。 程序的状态数据通常包含了数组、对象&#xff0…

(051)FPGA时钟--->(001)时钟介绍

(001)时钟介绍 1 目录 (a)FPGA简介 (b)Verilog简介 (c)时钟简介 (d)时钟介绍 (e)结束 1 FPGA简介 (a)FPGA(Field Programmable Gate Array)是在PAL (可编程阵列逻辑)、GAL(通用阵列逻辑)等可编程器件的基础上进一步发展的产物。它是作为专用集成电…

Python 植物大战僵尸游戏【含Python源码 MX_012期】

简介&#xff1a; "植物大战僵尸"&#xff08;Plants vs. Zombies&#xff09;是一款由PopCap Games开发的流行塔防游戏&#xff0c;最初于2009年发布。游戏的概念是在僵尸入侵的情境下&#xff0c;玩家通过种植不同种类的植物来保护他们的房屋免受僵尸的侵袭。在游…

【Go】爬虫数据解密_使用Go语言实现TripleDES加密和解密

是你多么温馨的目光 教我坚毅望着前路 叮嘱我跌倒不应放弃 没法解释怎可报尽亲恩 爱意宽大是无限 请准我说声真的爱你 &#x1f3b5; Beyond《真的爱你》 引言 Triple Data Encryption Standard (TripleDES 或 3DES) 是一种对称加密算法&#xff0c;它通…

C#面:请解释C#接口的显式实现有什么意义

C#接口的显式实现是指在实现接口成员时&#xff0c;使用接口名称进行限定的方式。这种方式可以在一个类中实现多个接口&#xff0c;并且可以避免接口成员之间的命名冲突。显式实现接口的成员只能通过接口类型来访问&#xff0c;而不能通过类的实例来访问。 显式实现接口的主要…

c语言回顾-函数递归

1.递归的介绍 1.1什么是递归 递归是指在一个函数的定义中调用自身的过程。简单来说&#xff0c;递归是一种通过重复调用自身来解决问题的方法。 递归包括两个关键要素&#xff1a;基本情况和递归情况。基本情况是指当问题达到某个特定条件时&#xff0c;不再需要递归调用&am…

Postman简介

目录 1.概述 2.诞生背景 3.历史版本 4.安装和卸载 5.菜单和菜单项 6.使用 7.应用场景 8.示例 8.1.简单的GET请求 8.2.POST请求提交数据 8.3.查询参数 9.未来展望 10.总结 1.概述 Postman是一款用于API开发、测试和文档管理的综合性工具。允许开发者和测试人员创建…

electron+js 通过图片地址复制图片

方法1&#xff1a;通过 FileReader 获取图片Buffer >创建 nativeImage 对象 function copyImageToClipboard(imageUrl) {let xhr new XMLHttpRequest();xhr.open(get, imageUrl, true);xhr.responseType blob;xhr.onload function () {if (this.status 200) {let reader…

Python语言例题集(015)

#!/usr/bin/python3 #使用列表模仿队列的操作。 class Queue(): def init(self): self.queue[] def enqueue(self,data):self.queue.insert(0,data)def dequeue(self):if len(self.queue):return self.queue.pop()return "队列是空的"qQueue() q.enqueue(‘Grape’…