【NOIP2013提高组】华容道

article/2025/10/7 6:50:29

题目背景

NOIP2013 提高组 Day2 试题。

题目描述

小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。 

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 
1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的; 
2. 有些棋子是固定的,有些棋子则是可以移动的; 
3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。 

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EXi 行第 EYi 列,指定的可移动棋子的初始位置为第 SXi 行第 SYi 列,目标位置为第 TXi 行第 TYi 列。 

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

输入格式

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。 

接下来的 q 行,每行包含 6 个整数依次是 EXi、EYi、SXi、SYi、TXi、TYi,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。 

输出格式

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出 -1。

样例数据 1

输入

3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2

输出

2
-1

备注

【样例说明】 
棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。 

1.第一次游戏,空白格子的初始位置是 (3,2)(图中空白所示),游戏的目标是将初始位置在 (1,2) 上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置 (2,2)(图中红色的格子)上。

移动过程如下:

2.第二次游戏,空白格子的初始位置是 (1,2)(图中空白所示),游戏的目标是将初始位置在 (2,2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3,2) 上。

要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置 (2,2) 上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置,游戏无法完成。

【数据范围】 

对于 30% 的数据,1≤n,m≤10,q=1; 
对于 60% 的数据,1≤n,m≤30,q≤10; 
对于 100% 的数据,1≤n,m≤30,q≤500。 

 

杂谈:

       我。。。(此处省略1000字吐槽)

       在考场上就算想到正解我也不会去写的,写正解的时间是暴力的4倍。。。

     我先写的DFS发现DFS不仅慢而且不好处理,于是弃疗写BFS在洛谷上得了80分,由于对洛谷飞快的评测机实在不放心又在接近CCF老爷机的机子上测得了70分(这个应该准确些),于是一个晚上没了。。。

       然后第二天刚了一上午终于把正解调出来了。。。

解析:

       先说暴力70分怎么写,直接BFS,记录的状态就是当前空格子和目标格子所在位置,非常好写且信价比高。

      然后是正解。因为只有空白块在指定棋子的旁边,指定棋子才能移动,而且指定棋子每次移动后,空白块仍然与指定棋子相邻。所以令move[x][y][k][l]表示指定棋子在(x,y),空白块在与指定棋子相邻的k方向,要将空白块移动到与指定棋子相邻的l方向需要的步数。那么首先把move预处理出来,在每一次讯问中,把空白格移到指定棋子相邻的存在的格子,做一次spfa,就可以了。

      spfa:令f[x][y][k]表示指定棋子在(x,y),空白块在与指定棋子相邻的k方向的状态需要的最少步数。转移显然,(xx,yy)是要移动到的方向,i表示指定格子要向i方向走,k1指移动后空白块在与指定棋子相邻的k方向,k1即是i的相反方向,那么

       f[x][y][k]+move[x][y][k][i]+1==>f[xx][yy][k1]

       至于复杂度,我无法准确说出来,还请各位dalao赐教。

总结:

       函数内变量名不要重复!否则很难检查到!

       数组在不超内存的情况定大点,否则可能会有边界问题!否则很难检查到!

 

代码(70分):

#include <bits/stdc++.h>
using namespace std;const int Max=31;
const int fx[5]={0,1,0,-1,0};
const int fy[5]={0,0,1,0,-1};
int n,m,ans,q;
int sx,sy,tx,ty,x,y;
int num[Max][Max],vis[Max][Max][Max][Max];
struct shu{int x,y,sx,sy,step;};
shu p[5000001];inline int get_int()
{int x=0,f=1;char c;for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());if(c=='-') f=-1,c=getchar();for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';return x*f;
}inline int bfs()
{int head=0,tail=1;p[1].x=x,p[1].y=y,p[1].sx=sx,p[1].sy=sy;while(head<tail){int x=p[++head].x,y=p[head].y;for(int i=1;i<=4;i++){int x1=x+fx[i],y1=y+fy[i],xx=p[head].sx,yy=p[head].sy;if(x1==xx&&y1==yy) xx=x,yy=y;if(x1<1||x1>n||y1<1||y1>m||!num[x1][y1]||vis[x1][y1][xx][yy]) continue;tail++;p[tail].sx=xx,p[tail].sy=yy,p[tail].x=x1,p[tail].y=y1,p[tail].step=p[head].step+1;vis[x1][y1][xx][yy]=1;if(p[tail].sx==tx&&p[tail].sy==ty) return p[tail].step;}}return -1;
}int main()
{n=get_int(),m=get_int(),q=get_int();for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)num[i][j]=get_int();while(q--){memset(vis,0,sizeof(vis));x=get_int(),y=get_int(),sx=get_int(),sy=get_int(),tx=get_int(),ty=get_int();if(sx==tx&&sy==ty) cout<<"0\n";else{ans=bfs();cout<<ans<<"\n";}}return 0;
}

代码(100分):

#include <bits/stdc++.h> 
using namespace std;const int Max=35;
const int fx[5]={0,1,0,-1};
const int fy[5]={1,0,-1,0};
int n,m,q,head,tail,tot,ans;
int num[Max][Max],dis[Max][Max][5],move[Max][Max][5][5];
bool vis[Max][Max],v[Max][Max][5];
int p[1000000][5],d[1000000][5];inline void bfs(int x,int y,int k1,int k2)
{int sx=x+fx[k1],sy=y+fy[k1],tx=x+fx[k2],ty=y+fy[k2];if((!num[sx][sy])||(!num[tx][ty])) return;head=0,tail=1;p[1][1]=sx,p[1][2]=sy;memset(vis,0,sizeof(vis));vis[x][y]=vis[sx][sy]=1;while(head<tail){head++;int xx=p[head][1],yy=p[head][2];for(int i=0;i<=3;i++){int x1=xx+fx[i],y1=yy+fy[i];if(!vis[x1][y1] && num[x1][y1]){vis[x1][y1]=1;p[++tail][1]=x1,p[tail][2]=y1,p[tail][0]=p[head][0]+1;if(x1==tx&&y1==ty) {move[x][y][k1][k2]=p[tail][0];return;}}}}
}inline void pre()
{memset(move,43,sizeof(move));for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(num[i][j])for(int k=0;k<=3;k++)for(int l=0;l<=3;l++)if(l==k) move[i][j][k][l]=0;else bfs(i,j,k,l);
}inline void calc(int x,int y,int sx,int sy)
{head=0,tail=1,tot=0;p[1][1]=x,p[1][2]=y,p[1][0]=0;memset(vis,0,sizeof(vis));vis[x][y]=vis[sx][sy]=1;while(head<tail){head++;int xx=p[head][1],yy=p[head][2];for(int i=0;i<=3;i++){int x1=xx+fx[i],y1=yy+fy[i];if(num[x1][y1]&&!vis[x1][y1]){vis[x1][y1]=1;p[++tail][0]=p[head][0]+1;p[tail][1]=x1,p[tail][2]=y1;}else if(x1==sx&&y1==sy) d[++tot][1]=x1,d[tot][2]=y1,d[tot][0]=p[head][0],d[tot][3]=(i+2)%4;}}
}inline void SPFA()
{memset(v,0,sizeof(v));for(int i=1;i<=tot;i++) dis[d[i][1]][d[i][2]][d[i][3]]=d[i][0],v[d[i][1]][d[i][2]][d[i][3]]=1;head=0,tail=tot;while(head<tail){head++;int x=d[head][1],y=d[head][2];v[x][y][d[head][3]]=0;for(int i=0;i<=3;i++){int x1=x+fx[i],y1=y+fy[i];if(dis[x1][y1][(i+2)%4] > dis[x][y][d[head][3]]+move[x][y][d[head][3]][i]+1){dis[x1][y1][(i+2)%4]=dis[x][y][d[head][3]]+move[x][y][d[head][3]][i]+1;if(!v[x1][y1][(i+2)%4]){tail++;d[tail][1]=x1,d[tail][2]=y1,d[tail][3]=(i+2)%4;v[x1][y1][(i+2)%4]=1;}} }}
}int main()
{scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) scanf("%d",&num[i][j]);pre();while(q--){int x,y,sx,sy,tx,ty;scanf("%d%d%d%d%d%d",&x,&y,&sx,&sy,&tx,&ty);if(sx==tx&&sy==ty) {cout<<"0\n";continue;}memset(dis,43,sizeof(dis));calc(x,y,sx,sy);SPFA();ans=dis[0][0][0];for(int i=0;i<=3;i++) ans=min(ans,dis[tx][ty][i]);if(ans==dis[0][0][0]) cout<<"-1\n";else cout<<ans<<"\n";}return 0;
}

 


http://chatgpt.dhexx.cn/article/Le4QH2dV.shtml

相关文章

【NOIP2013提高组】花匠

题目背景 NOIP2013 提高组 Day2 试题。 题目描述 花匠栋栋种了一排花&#xff0c;每株花都有自己的高度。花儿越长越大&#xff0c;也越来越挤。栋栋决定把这排中的一部分花移走&#xff0c;将剩下的留在原地&#xff0c;使得剩下的花能有空间长大&#xff0c;同时&#xff…

【NOIP2013提高组】积木大赛

题目背景 NOIP2013 提高组 Day2 试题 题目描述 春春幼儿园举办了一年一度的“积木大赛”。今年比赛的内容是搭建一座宽度为 n 的大厦&#xff0c;大厦可以看成由 n 块宽度为 1 的积木组成&#xff0c;第 i 块积木的最终高度需要是 hi。 在搭建开始之前&#xff0c;没有任何…

7.15 NOIP 2013

NOIP 2013 DAY 1 DAY1 T1 转圈游戏 快速幂模板 #include<bits/stdc.h> using namespace std; int n,m,k,x; long long ans; long long cmd(long long a,long long b){long long sum1;for(;a;a>>1){if(a&1){sumsum*b%n;}bb*b%n; } return sum; } int main(…

noip2013 day2

一道纯模拟就可以过&#xff08;水水水&#xff09;。 考试时本蒟蒻甚至写了个线段树&#xff0c;然后发现其实不如直接模拟。 模拟思路&#xff1a; 从1到n枚举每个最长的不为0的序列&#xff0c;每次每个数减去其中剩余的最小值&#xff0c;答案加上这个最小值&#xff0c…

noip2013

D1&#xff1a; T1&#xff1a;快速幂 #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cstdlib> #include<cmath> #define LL long long using namespace std; LL n,m,k,x; inline LL quickpow(LL…

解题报告:NOIP2013 车站分级(拓扑序递推求解差分约束、建图优化O(n+m)) 超详细讲解

本题是2013年NOIP普及组的压轴题 差分约束裸题。 计算当前线路中最小的级别&#xff08;比较始发站和终点站&#xff09;。 整条线路中所有大于这个级别的都必须停靠 所有未停靠的站点的级别一定小于这个级别 也就是说所有未停靠的即为级别低&#xff0c;记为A 所有停靠的站点…

[NOIP2013]记数问题

[NOIP2013]记数问题 1.题目2.分析3.代码方法1&#xff1a;将每个数字的每一位单独算出方法2&#xff1a;转换为字符串再进行遍历 4.反思总结5.更新日志 1.题目 题目链接 题号&#xff1a;NC16538 时间限制&#xff1a;C/C 1秒&#xff0c;其他语言2秒 空间限制&#xff1a;C/C…

ARMv8体系结构基础04:算术和移位指令

目录 1 数据处理指令概述 2 加法指令详解 2.1 ADD指令 2.1.1 ADD&#xff08;extended register&#xff09;指令编码分析 2.1.2 ADD&#xff08;extended register&#xff09;指令编码验证 2.1.3 ADD&#xff08;immediate&#xff09;指令编码分析 2.1.4 ADD&#xf…

8086CPU指令系统--汇编语言逻辑运算和移位操作指令

文章目录 一、逻辑运算指令1、逻辑‘与’指令 AND2、逻辑‘或’指令 OR3、逻辑“非”指令 NOT4、逻辑“异或” XOR5、测试指令TEST 二、移位指令1&#xff09;非循环移位1、算数左移SAL和逻辑左移SHL2、逻辑右移SHR3、算术右移SAR 2&#xff09;循环移位1、带CF的循环左移 RCL2…

arm64汇编学习-(3)算术与移位指令

arm64汇编学习-&#xff08;3&#xff09;算术与移位指令 1 数据处理指令1.1 check the C condition of adds, adc,cmp1.1.1 测试示例程序1.1.2 执行之前1.1.3 执行之后1.1.3.1 ldr和mov指令之后1.1.3.2 ads和adc指令之后1.1.3.3 cmp和adc指令之后 1.2 cmp和sbc指令的综合运用1…

汇编语言——逻辑运算和移位指令

逻辑运算和移位指令 逻辑运算指令 逻辑与AND 格式 AND reg, imm/reg/mem ;reg←reg^imm/reg/mem AND mem, imm/reg ; mem←-mem ^ imm/reg功能:对两个操作数执行按位的逻辑与运算&#xff0c;结果送到目的操作数说明: (1)按位的逻辑与运算; (2)操作数不能同时为存储器操作数…

汇编语言基础之 移位指令

原文: http://bdxnote.blog.163.com/blog/static/ 移位指令是一组经常使用的指令,包括:算数移位、逻辑移位、双精度移位、循环移位、带进位的循环移位; 移位指令都有一个指定需要移动的二进制位数的操作数,该操作数可以是立即数,也可以是CL的值;在8086中,该操作数只能是1,但是在…

x86汇编_移位和循环移位指令简介_笔记46

移位指令与前面介绍的按位操作指令一起形成了汇编语言最显著的特点之一。位移动 (bit shifting) 意味着在操作数内向左或向右移动。x86 处理器在这方面提供了相当丰富的指令集如下表所示&#xff0c;这些指令都会影响溢出标志位和进位标志位。 英文全称汇编指令中文翻译说明意…

PLC移位循环指令

PLC移位循环指令 一、移位指令 移位指令包括无符号数移位和有符号数移位。 其中无符号数移位包含字左移指令、字右移指令、 双字左移指令和双字右移指令&#xff1b;有符号数移位包含整数右移指令和双整数右移指令。 1、无符号数移位指令 &#xff08;1&#xff09;字左移指…

ARM64体系结构编程3-算数和移位指令

条件操作码 条件标志位描述N负数标志&#xff08;上一次运算结果为负值&#xff09;Z零结果标志&#xff08;上一次运算结果为零&#xff09;C进位标志&#xff08;上一次运算结果发生了无符号溢出&#xff09;V溢出标志&#xff08;上一次运算结果发生了有符号溢出&#xff0…

逻辑、移位操作与空指令的实现

逻辑、移位操作和空指令的实现 1. 流水线数据相关的问题 流水线上经常会有一些被称为“相关”的情况发生&#xff0c;它使得指令序列中下一条指令无法按照设计的时钟周期执行&#xff0c;这些“相关”会降低流水线的性能。 1.1 流水线相关 流水线中的相关可分为&#xff1a…

汇编移位指令SHR,SAR,SAL/SHL,ROR,ROL,RCR,RCL

目录 逻辑右移SHR 算数右移SAR&#xff08;重点&#xff09; 算数/逻辑左移SAL/SHL(完成的操作都一样) 循环右移ROR 循环左移ROL 带进位循环右移RCR 带进位循环左移RCL 总结 例题 一 二 移位指令为双操作数指令&#xff0c;用于将目的的操作数中的二进制数移位。 目…

位移指令实现乘法、除法计算

前言 大家都知道51单片机是有乘法、除法指令的&#xff0c;不管是用C语言还是汇编语言&#xff0c;都是可以直接计算乘法、除法的&#xff0c;我以为&#xff0c;-&#xff0c;*&#xff0c;/ 这些算术运算是单片机的标配&#xff0c;而我公司使用的应广单片机居然没有乘法、除…

微机原理——移位指令

例题 思路 选择移位语句&#xff0c;右移&#xff0c;将AL移出的送入DX左端&#xff0c;将BL移出的送入DX左端。循环八次 MOV AL,01100101B; MOV BL,11011010B; XOR DX,DX;两个值相同&#xff0c;异或结果为0。等效&#xff1a;MOV DX,0 MOV CX,8;count L1: SHR AL,1;逻辑右…

汇编语言---移位指令

移位指令是一组经常使用的指令,包括:算数移位、逻辑移位、双精度移位、循环移位、带进位的循环移位; 移位指令都有一个指定需要移动的二进制位数的操作数,该操作数可以是立即数,也可以是CL的值;在8086中,该操作数只能是1,但是在其后的CPU中,该立即数可以是定义域[1,31]之内的数…