一道码量比较大的套路广搜题……

首先看数据 \(n,m \leq 1000\) 不是特别恶心,不难想到广搜。

由于这道题每走一步的代价不是 \(1\),所以并不能保证每次搜到的点就是最优解。那么可以考虑用一个数组 \(h[i][j][sun][kill]\) 来维护一下。

其中的 \({i,j,sun,kill}\) 是记录一个状态,表示在走到点 \((i,j)\) 时是否有太阳花田和楼关剑。而 \(h[i][j][sun][kill]\) 则表示到达这个状态下的最短路径。

这样就可以有效的剪枝了,因为有了最短路数组的维护我们可以排除到达当前状态没有最短路优的路径。而如果比最短路优,那么最短路就更新为当前路径,效率将有所提高。

期望得分:\(80-90\)

接下来考虑用优先队列优化。

可以这样想,我们把所有广搜的状态存入优先队列,每次弹出当前最短的状态,可以证明其扩展到的点一定也是最短的(因为没有负环)。

于是重载一下小于号运算符就行了,搜到终点就一定是最短路,然后把状态 \((i,j,sun,kill)\) 打上标记即可。其实和 \(\operatorname{dijkstra}\) 方法类似。

时间复杂度 \(O(4nm\) \(log\) \(4nm)\)

\(\operatorname{Coding}\) 时注意两点:

  • 传送门前后都要判一下标记

  • 楼观剑可以经过而不取

#include<bits/stdc++.h>
using namespace std;
const int max_n=1000+5;
int a[max_n][max_n];
bool h[max_n][max_n][2][2];//标记状态
struct node{
int x,y,f,sun,kill;
bool operator<(const node&a)const{//重载小于运算符
return f>a.f;
}
};
priority_queue<node>q;
vector< pair<int,int> >s;//传送门
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//上下左右
int main(){
ios::sync_with_stdio(false);
int n,m;cin>>n>>m;
int fx,fy,lx,ly;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch;cin>>ch;
if(ch=='S')fx=i,fy=j;
if(ch=='E')lx=i,ly=j;
if(isdigit(ch))a[i][j]=ch-'0';
if(ch=='X')a[i][j]=6,s.push_back(make_pair(i,j));
}
}
h[fx][fy][0][0]=1;
q.push({fx,fy,0,0,0});
while(!q.empty()){
int x=q.top().x,y=q.top().y,f=q.top().f;
int sun=q.top().sun,kill=q.top().kill;
if(x==lx&&y==ly){//到终点一定是最优解
cout<<f<<"\n";
return 0;
}
for(int i=0;i<4;i++){
int tx=x+dir[i][0],ty=y+dir[i][1];
if(!(tx>=1&&tx<=n&&ty>=1&&ty<=m))continue;//不能超边界
if(a[tx][ty]==6){//传送门
if(h[tx][ty][sun][kill])continue;//这里不写84分AC再见
for(int j=0;j<s.size();j++){//枚举下一个传送门
int ttx=s[j].first,tty=s[j].second;
if(tx==ttx&&ty==tty)continue;//传送门当然不能自己传给自己哦
if(h[ttx][tty][sun][kill])continue;
h[ttx][tty][sun][kill]=1;//标记
q.push({ttx,tty,f+2,sun,kill});//入队
}
}
if(a[tx][ty]==0){//普通的点
if(h[tx][ty][sun][kill])continue;
h[tx][ty][sun][kill]=1;
q.push({tx,ty,f+1,sun,kill});
}
if(a[tx][ty]==1&&kill){//这里是墙,要经过必须要有楼观剑
if(h[tx][ty][sun][kill])continue;
h[tx][ty][sun][kill]=1;
q.push({tx,ty,f+1,sun,kill});
}
if(a[tx][ty]==2){//小怪兽
if(h[tx][ty][sun][kill])continue;
h[tx][ty][sun][kill]=1;
if(kill||sun)q.push({tx,ty,f+1,sun,kill});//如果有楼观剑或太阳花就可以直接上去
else q.push({tx,ty,f+4,sun,kill});//否则要花时间把它打死
}
if(a[tx][ty]==3){//大怪兽(和小怪兽同理)
if(h[tx][ty][sun][kill])continue;
h[tx][ty][sun][kill]=1;
if(kill||sun)q.push({tx,ty,f+1,sun,kill});
else q.push({tx,ty,f+9,sun,kill});
}
if(a[tx][ty]==4){//太阳花,只要经过就能得到
if(h[tx][ty][1][kill])continue;
h[tx][ty][1][kill]=1;
q.push({tx,ty,f+1,1,kill});
}
if(a[tx][ty]==5){//楼观剑
if(h[tx][ty][sun][1]==0){//取
h[tx][ty][sun][1]=1;
q.push({tx,ty,f+6,sun,1});
}
if(h[tx][ty][sun][kill]==0){//不取
h[tx][ty][sun][kill]=1;
q.push({tx,ty,f+1,sun,kill});
}
}
}
q.pop();
}
cout<<"We want to live in the TouHou World forever\n";
return 0;
}

\(\operatorname{Update}\) \(\operatorname{On}\) \(\operatorname{2019.08.26}\)

题解 洛谷P4872 【OIer们的东方梦】的更多相关文章

  1. 洛谷 P5640 【CSGRound2】逐梦者的初心

    洛谷 P5640 [CSGRound2]逐梦者的初心 洛谷传送门 题目背景 注意:本题时限修改至250ms,并且数据进行大幅度加强.本题强制开启O2优化,并且不再重测,请大家自己重新提交. 由于Y校的 ...

  2. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  3. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  4. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  5. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  6. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  7. 题解-洛谷P4859 已经没有什么好害怕的了

    洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...

  8. 题解-洛谷P5217 贫穷

    洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...

  9. 题解 洛谷 P2010 【回文日期】

    By:Soroak 洛谷博客 知识点:模拟+暴力枚举 思路:题目中有提到闰年然后很多人就认为,闰年是需要判断的其实,含有2月29号的回文串,前四位是一个闰年那么我们就可以直接进行暴力枚举 一些小细节: ...

随机推荐

  1. python文件夹操作

    1.遍历文件夹下所有文件2.将后缀为.DCM的文件复制到指定文件夹 import os import shutil def all_path(dirname): result = []#所有的文件 f ...

  2. 将本机电脑作为自己的网站服务器--基于XAMPP在本地建立wordPress网站

    "我不敢说自己从未担心害怕过. 实际上我希望少一点担心害怕,因为它让我分心,让我的神经系统备受煎熬".----马斯克 周日,搞了大半天,为了熟悉wordPress,先在自己的电脑上 ...

  3. unexpected end of file while looking for precompiled headerdirective Add directive to 'stdafx.h' or rebuild precompiled header错误

    解决方式: 项目工程右键->propertity(属性),选择不用于预编译头 原因: C++的编译过程如下: 当头文件很多时,预编译过程需要耗费大量时间,为了减少重复编译的次数,C和C++提供了 ...

  4. Linux进程状态详解及状态转换

        学而不思则罔,思而不学则殆.    Linux下,进程状态有五种 : 运行态,可中断睡眠态,不可中断睡眠态,停止态和追踪态 运行态表示进程可执行或者正在执行, 可中断睡眠态表示进程被阻塞,等条 ...

  5. kali_Airmon-ng第一次渗透测试

    再看了一些资料之后,决定自己整理一下进行第一次测试,测试目标,自己宿舍的WIFI.教程仅供学习参考 断开kali连接的wifi,并检查网卡状态 airmon-ng 开启无线网卡的监控模式 airmon ...

  6. java.lang.IllegalArgumentException: Expected authority at index 7: http:// 异常的原因

    今天遇到个错误,异常信息  java.lang.IllegalArgumentException: Expected authority at index 7: http://  ,中文意思就是说参数 ...

  7. Python 获取本月的最后一天

    一.需求 现在有一个场景,需要每月的最后一天,发送一封邮件. 二.获取本月最后一天 有没有办法使用Python的标准库轻松确定(即一个函数调用)给定月份的最后一天? 答案是有的,使用 datetime ...

  8. 在 WPF 中获取一个依赖对象的所有依赖项属性

    原文:在 WPF 中获取一个依赖对象的所有依赖项属性 本文介绍如何在 WPF 中获取一个依赖对象的所有依赖项属性. 本文内容 通过 WPF 标记获取 通过设计器专用方法获取 通过 WPF 标记获取 p ...

  9. QLineEdit 按键Tab键时 显示历史记录

    #LineEdit添加历史记录功能,按下回车添加至历史中 class LineEditWithHistory(QtWidgets.QLineEdit): def __init__(self, pare ...

  10. MQTT协议中的topic

    1.MQTT协议中的topic 定阅与发布必须要有主题,只有当定阅了某个主题后,才能收到相应主题的payload,才能进行通信. 2. 主题层级分隔符--"/" 主题层级分隔符使得 ...