当前位置: 首页 > news >正文

???牛客周赛55:虫洞操纵者

题目描述

          \,\,\,\,\,\,\,\,\,\,你需要在一个可以上下左右移动的 n×nn\times nn×n 棋盘上解开一个迷宫:棋盘四周都是墙;每个方格要么是可以通过的空方格 ′0′\sf '0'′0′ ,要么是不可通过的墙方格 ′1′\sf '1'′1′ ;你可以沿着空方格通行;你已经被传送到了迷宫的左上角(第 111 行第 111 列的位置),你知道终点位于迷宫右下角(第 nnn 行第 nnn 列的位置)。
          \,\,\,\,\,\,\,\,\,\,别人都不知道的是,你是一个虫洞大师,当你所在的位置能同时看到左右两侧或上下两侧最近的那两面相对的墙时,你可以在这两面墙上开启虫洞,靠近后从一侧进入,穿越它到达另一侧。
          \,\,\,\,\,\,\,\,\,\,现在,你准备好以最短的步数离开迷宫了吗!

输入描述:

 

          \,\,\,\,\,\,\,\,\,\,第一行输入一个整数 n(2≤n≤103)n\left(2\le n \le 10^3\right)n(2≤n≤103) 代表迷宫的大小。

          \,\,\,\,\,\,\,\,\,\,此后 nnn 行,第 iii 行输入 nnn 个整数 ai,1,ai,2,…,ai,n(0≤ai,j≤1)a_{i,1},a_{i,2},\dots,a_{i,n} \left(0\le a_{i,j}\le 1\right)ai,1​,ai,2​,…,ai,n​(0≤ai,j​≤1) 代表迷宫中第 iii 行第 jjj 列这个格子中的情况,其中 000 代表空方格,111 代表墙方格。保证起点和终点不为墙壁。

输出描述:

          \,\,\,\,\,\,\,\,\,\,在一行上输出一个整数,代表离开迷宫需要的最短步数,如果无论如何都无法离开迷宫,则直接输出 −1-1−1 。

示例1

输入

复制5 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0

5
0 0 0 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0
1 0 0 0 0

输出

复制3

3

说明

 

          \,\,\,\,\,\,\,\,\,\,该样例示意图如下图所示。全部墙壁的位置都使用粗黑线标注。先从 (1,1)(1,1)(1,1) 向右移动一步走到 (1,2)(1,2)(1,2) ,此时可以开启一个虫洞(使用紫色箭头标注),向上移动一步到达 (5,2)(5,2)(5,2) ;此时可以开启第二个虫洞(使用红色箭头标注),向左移动一步到达 (5,5)(5,5)(5,5) 。

          \,\,\,\,\,\,\,\,\,\,

          \,\,\,\,\,\,\,\,\,\,注意,在该样例中,不能直接从 (1,1)(1,1)(1,1) 开启虫洞(使用黑色箭头标注)到达 (1,5)(1,5)(1,5) ,因为 (1,4)(1,4)(1,4) 存在两面墙遮挡了视线;不能直接从 (4,3)(4,3)(4,3) 开启虫洞(使用绿色箭头标注)到达 (1,3)(1,3)(1,3) ,因为这两面墙不是相对的。

          \,\,\,\,\,\,\,\,\,\,

示例2

输入

复制5 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0

5
0 0 0 1 0
1 1 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 1 0

输出

复制5

5

说明

          \,\,\,\,\,\,\,\,\,\,

示例3

输入

复制2 0 1 1 0

2
0 1
1 0

输出

复制-1

-1

做法

#include<bits/stdc++.h>
using namespace std;int n;
int a[1010][1010];
int vis[1010][1010];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};struct ty{int x,y;int dis;
};int sign;
queue<ty> q;void bfs(){q.push({1,1,0});while(!q.empty()){ty tmp=q.front();q.pop();if(tmp.x==n&&tmp.y==n){cout<<tmp.dis;sign=1;return ;}if(vis[tmp.x][tmp.y]) continue;vis[tmp.x][tmp.y]=1;for(int i=0;i<4;i++){int xx=dx[i]+tmp.x;int yy=tmp.y+dy[i];if(a[xx][yy]==0){//墙壁//反方向搜,直到碰到墙壁while(a[xx-dx[i]][yy-dy[i]]) xx=xx-dx[i],yy=yy-dy[i];}if(vis[xx][yy]) continue;q.push({xx,yy,tmp.dis+1});}}
}int main(){scanf("%d",&n);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cin>>a[i][j];a[i][j]^=1;//异或一下的话路变成1,墙壁变成0,四周的墙壁也是0}}bfs();if(sign==0) cout<<-1;}

我的做法错了,不知道为啥,和题解的做法不一样的就是我四周的墙壁单独处理了。然后穿墙的时候找穿越的位置也不是一个个暴力找,而是用了二分函数找。但是只过了20%,实在是找不到为什么。

#include<bits/stdc++.h>
using namespace std;int n;
int a[1010][1010];
vector<int> h[1010],l[1010];
int vis[1010][1010];
int vis1[1010][1010][4];
int dx[]={0,0,1,-1};//右左下上
int dy[]={1,-1,0,0};struct ty{int x,y;int dis;
};int sign;
queue<ty> q;void bfs(){q.push({1,1,0});while(!q.empty()){ty tmp=q.front();q.pop();vis[tmp.x][tmp.y]=1;if(tmp.x==n&&tmp.y==n){cout<<tmp.dis;sign=1;return ;}for(int i=0;i<4;i++){int xx=dx[i]+tmp.x;int yy=tmp.y+dy[i];//四周墙壁if(yy<1){//左if(h[xx].size()==0&&!vis[xx][n]) q.push({xx,n,tmp.dis+1});else if(h[xx].size()!=0&&!vis[xx][h[xx][0]-1])q.push({xx,h[xx][0]-1,tmp.dis+1});continue;}if(xx<1){//上if(l[yy].size()==0&&!vis[n][yy]) q.push({n,yy,tmp.dis+1});else if(l[yy].size()!=0&&!vis[l[yy][0]-1][yy]) q.push({l[yy][0]-1,yy,tmp.dis+1});continue;}if(yy>n){//右if(h[xx].size()==0&&!vis[xx][1]) q.push({xx,1,tmp.dis+1});else if(h[xx].size()!=0&&!vis[xx][h[xx][h[xx].size()-1]+1]) q.push({xx,h[xx][h[xx].size()-1]+1,tmp.dis+1});continue;}if(xx>n){//下if(l[yy].size()==0&&!vis[1][yy]) q.push({1,yy,tmp.dis+1});else if(l[yy].size()!=0&&!vis[l[yy][l[yy].size()-1]+1][yy]) q.push({l[yy][l[yy].size()-1]+1,yy,tmp.dis+1});continue;}if(a[xx][yy]==1){//墙壁if(vis1[xx][yy][i]) continue;vis1[xx][yy][i]=1;if(i==0) {//右if(h[xx].size()==1) q.push({xx,1,tmp.dis+1});else{int id=lower_bound(h[xx].begin(),h[xx].end(),yy)-h[xx].begin()-1;if(id!=-1) q.push({xx,h[xx][id]+1,tmp.dis+1});else q.push({xx,1,tmp.dis+1});}}if(i==1){//左if(h[xx].size()==1) q.push({xx,n,tmp.dis+1});else{int id=upper_bound(h[xx].begin(),h[xx].end(),yy)-h[xx].begin();if(id!=h[xx].size()) q.push({xx,h[xx][id]-1,tmp.dis+1});else q.push({xx,n,tmp.dis+1});}}if(i==2){//下if(l[yy].size()==1) q.push({1,yy,tmp.dis+1});else{int id=lower_bound(l[yy].begin(),l[yy].end(),xx)-l[yy].begin()-1;if(id!=-1) q.push({l[yy][id]+1,yy,tmp.dis+1});else q.push({1,yy,tmp.dis+1});}}if(i==3){//上if(l[yy].size()==1) q.push({n,yy,tmp.dis+1});else{int id=upper_bound(l[yy].begin(),l[yy].end(),yy)-l[yy].begin();if(id!=l[yy].size()) q.push({l[yy][id]-1,yy,tmp.dis+1});else q.push({n,yy,tmp.dis+1});}}}else {//正常的路if(vis[xx][yy]) continue;q.push({xx,yy,tmp.dis+1});}}}
}int main(){scanf("%d",&n);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cin>>a[i][j];if(a[i][j]) {h[i].push_back(j);l[j].push_back(i);} }}for(int i=1;i<=n;i++){sort(l[i].begin(),l[i].end());sort(h[i].begin(),h[i].end());}bfs();if(sign==0) cout<<-1;}

http://www.lryc.cn/news/427222.html

相关文章:

  • Unity3D开发之OnCollisionXXX触发条件
  • spfa()算法(求最短路)
  • 聊聊国产数据库的生态系统建设
  • JDK源码解析:LinkedList
  • drawio的问题
  • 零基础学习Redis(3) -- Redis常用命令
  • 响应式Web设计:纯HTML和CSS的实现技巧-1
  • FrereRTOS事件组
  • 【经典算法】BFS_最短路问题
  • 【题目/训练】:双指针
  • LLVM - 编译器后端-指令选择
  • ES+FileBeat+Kibana日志采集搭建体验
  • Dockerfile常用指令详解
  • 【vue】浏览器兼容相关
  • 【区块链+金融服务】基于区块链的区域股权金融综合服务平台 | FISCO BCOS应用案例
  • string字符串和json对象相互转换问题
  • 【生成式人工智能-十一一个不修改模型就能加速语言模型生成的方法】
  • Rust 错误处理
  • 程序与进程 linux系统
  • 使用MongoDB构建AI:Story Tools Studio将生成式AI引入Myth Maker AI游戏
  • 鸿蒙UIAbility组件概述(二)
  • Oracle(70)如何优化SQL查询?
  • 深度剖析:Jenkins构建任务无法中断的原因及解决方案
  • 【YOLO】常用脚本
  • Springboot IOC DI理解及实现+JUnit的引入+参数配置
  • CeresPCL 最小二乘插值(曲线拟合)
  • 【TCP/IP】自定义应用层协议,常见端口号
  • Frida 的下载和安装
  • 后端开发刷题 | 链表内指定区间反转【链表篇】
  • 【NVMe系列-提问页与文章总结页面】