NOIP2013 华容道

图论好题。 介于网上全是些令蒟蒻头昏的题解和排版一塌糊涂以及过于详细的题解。。。蒟蒻记录一下。。

显然需要将白格移动到 \(s\) 相邻格,然后交换 \(s\) 与白格,再将白格移动到 \(s\) 相邻格,然后交换 \(s\) 与白格……最后一步将白格移动到 与 \(s\) 相邻的 \(t\) ,交换白格与 \(s\)。

我们考虑到,将格子 \(a\) 从 \((i,j)\) 移动到相邻的格子 \(b\),需要让白格先移动到 \(b\),之后交换 \(a\) 与白格。显然 \(a\) 下一步还是要继续往其他方向移动的,所以白格仍然需要移动到格子 \(a\) 的某个相邻格。

我们写了一个 bfs ,可以在白格在 \((ei,ej)\), s \((si,sj)\) 的时候处理一些值,接下来详细阐述。


现在所阐述的 bfs 是在代码中 \(k=0,1,2,3\) 时的 bfs ,用于预处理建图。

设置状态 \((i,j,k)\) 表示 格子 \(s\) 在 \((i,j)\) ,白格在 \((i,j)\) 的方向 \(k\) 处。( \(k\) : left right up down,用0,1,2,3表示)。

可以通过 bfs 计算出 状态 \((i,j,k)\) 时, 白格开始移动,移动到棋盘上任意一个格子 \((x,y)\) 的花费 \(dis_{x,y}\)。注意,在代码中,为了方便标记哪些是不可能移动到的点,将所有 \(dis_{x,y}\) 都加一了,但在题解中 \(dis_{x,y}\) 仍然是原先的值。

从状态 \((i,j,k)\) 转移到另一个状态,有两种情况。

  • 白格与 \(s\) 交换,在状态 \((si,sj,k)\) 与 \((ei,ej,k\and 1)\) 之间连边 1。
  • 白格移动到了一个与 \(s\) 相邻的位置 \((xx,yy)\) ,在状态 \((si,sj,k)\) 与状态 \((si,sj,i)\) 之间连边 \(dis_{xx,yy}\).

如果要计算状态 \((x1,y1,k1)\) 到状态 \((x2,y2,k2)\) 之间的最小花费,只需要跑最短路即可。

也就是说,我们把状态作为点,花费作为边建图。


现在阐述的是在代码中 \(k=4\) 时的 bfs,这是处理 白格到 初始格的相邻格 花费的 bfs。

仍然先处理出所有的 \(dis_{x,y}\) , 意义与求法同 \(k=0,1,2,3\) 时一样。将与 \(s\) 相邻格的 \(dis_{x,y}\) 赋值在 dist 上。

最后计算答案,只需要 spfa 计算 \((tx,ty,0/1/2/3)\) 到 \((sx,sy,0/1/2/3)\) 的最短路。

#include<bits/stdc++.h>
using namespace std;
const int N=35,M=4010;
int n,m,q,mp[N][N],dis[N][N],dist[M];
bool vis[M];
int e,to[M*5],nxt[M*5],val[M*5],hd[M];
int dx[5]={-1,1,0,0};
int dy[5]={0,0,-1,1};
void add(int x,int y,int w){ to[++e]=y; nxt[e]=hd[x]; val[e]=w; hd[x]=e; }
void bfs(int ei,int ej,int si,int sj,int dir){
memset(dis,0,sizeof(dis));
queue<pair<int,int> >q;
q.push(make_pair(ei,ej)); dis[ei][ej]=1;
while(!q.empty()){
pair<int,int>w=q.front(); q.pop();
int x=w.first,y=w.second;
for(int i=0;i<4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(!mp[xx][yy]||dis[xx][yy]||xx==si&&yy==sj) continue;
dis[xx][yy]=dis[x][y]+1; q.push(make_pair(xx,yy));
}
}//白格向外疯狂移动处理步数
if(dir==4) return; for(int i=0;i<4;i++){
int xx=si+dx[i],yy=sj+dy[i];
if((xx==ei&&yy==ej)||!dis[xx][yy]) continue;
add(si*30*4+sj*4+dir,si*30*4+sj*4+i,dis[xx][yy]-1);//白格移动
}
add(si*30*4+sj*4+dir,ei*30*4+ej*4+(dir^1),1);//交换
return;
}
void spfa(int x,int y){
memset(dist,0x3f,sizeof(dist));
memset(vis,0,sizeof(vis)); queue<int>q;
for(int i=0;i<4;i++){
if(!dis[x+dx[i]][y+dy[i]]) continue;
int id=x*30*4+y*4+i; q.push(id);
dist[id]=dis[x+dx[i]][y+dy[i]]-1; vis[id]=1;
}
while(!q.empty()){
int id=q.front(); q.pop(); vis[id]=0;
// cout<<id<<endl;
for(int i=hd[id];i;i=nxt[i]){
int nxid=to[i],nxval=val[i];
// cout<<"nxid: "<<nxid<<endl;
if(dist[nxid]>dist[id]+nxval){
dist[nxid]=dist[id]+nxval;
if(vis[nxid]) continue;
vis[nxid]=1; q.push(nxid);
}
}
}
return;
}
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",&mp[i][j]);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!mp[i][j]) continue;
if(mp[i-1][j]) bfs(i-1,j,i,j,0);
if(mp[i+1][j]) bfs(i+1,j,i,j,1);
if(mp[i][j-1]) bfs(i,j-1,i,j,2);
if(mp[i][j+1]) bfs(i,j+1,i,j,3);
}
}
//预处理,建图
while(q--){
int ex,ey,sx,sy,tx,ty;
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
if(sx==tx&&sy==ty){ puts("0"); continue; } bfs(ex,ey,sx,sy,4); spfa(sx,sy); int ans=0x3f3f3f3f;
for(int i=0;i<4;i++) ans=min(ans,dist[tx*30*4+ty*4+i]);
(ans==0x3f3f3f3f)?puts("-1"):printf("%d\n",ans);
}
return 0;
}

[ NOIP2013 D2-T3 ] 华容道的更多相关文章

  1. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

  2. [NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

    [NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有 ...

  3. [NOIP2013 提高组] 华容道 P1979 洛谷

    [NOIP2013 提高组] 华容道 P1979 洛谷 强烈推荐,更好的阅读体验 经典题目:spfa+bfs+转化 题目大意: 给出一个01网格图,和点坐标x,y空格坐标a,b,目标位置tx,ty要求 ...

  4. [NOIP2016]愤怒的小鸟 D2 T3

    Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可以用它向第一象限发射一只红色的小鸟,小鸟们的 ...

  5. NOIP2013 D1 T3 货车运输

    好吧,遇上这种题,作为蒟蒻的我第一个想到的就是怎么打暴力,然而暴力都打不好QAQ!!!于是只能等教练讲解以后,然后在大犇的指导下终于做出来了. 对了,,好像还,没上题....: 题目描述 A 国有 n ...

  6. 洛谷1967货车运输 即 NOIP2013 DAY1 T3

    题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多 ...

  7. NOIP2013 DAY2 T3火车运输

    传送门 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况 ...

  8. 逛公园[NOIP2017 D2 T3](dp+spfa)

    题目描述 策策同学特别喜欢逛公园. 公园可以看成一张 \(N\)个点\(M\) 条边构成的有向图,且没有自环和重边.其中 1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值,代表策策经过这条 ...

  9. NOIP2012 D2 T3 疫情控制 洛谷P1084

    题目链接:https://www.luogu.org/problemnew/show/P1084 算法:倍增,二分答案,贪心 + 瞎搞.. 背景:上学长的数论课啥也听不懂,于是前去提高组找安慰.不巧碰 ...

  10. [NOIP2013提高组]华容道

    这道题第一眼看是暴力,然后发现直接暴力会TLE. 把问题转换一下:移动空格到处跑,如果空格跑到指定位置的棋子,交换位置. 这个可以设计一个状态:$[x1][y1][x2][y2]$,表示空格在$(x1 ...

随机推荐

  1. Linux proc文件系统小记

    序言: 当linux系统存在多个网口时(也可以是一个网口配置两个IP),每个网口配置不同的IP地址,并且分别连接到不同的电脑上,电脑分别配置与相连的网口统一网段的IP且将电脑网关设置为linux的网口 ...

  2. 大数据最后一公里——2021年五大开源数据可视化BI方案对比

    个人非常喜欢这种说法,最后一公里不是说目标全部达成,而是把整个路程从头到尾走了一遍. 大数据在经过前几年的野蛮生长以后,开始与数据中台的概念一同向着更实际的方向落地.有人问,数据可视化是不是等同于数据 ...

  3. private关键字理解

    private 意思: 私有的 私人的 不公开的 private 是一个修饰符可以用来修饰成员变量和方法 被private修饰的成员变量或成员方法,只能在本类中访问,针对private修饰的成员变量, ...

  4. Wpf读写Xaml文件

    前言 本文主要介绍Wpf读写Xaml文件. 读写实现 首先我们使用XamlWriter将Wpf的对象转换为Xaml字符串,代码如下: var btn = sender as Button; strin ...

  5. python循环以及控制语句

    python流程 学习完本篇,你将会通过python完成以下题目 试利用break语句求解2-100之间的素数. (1)素数是指除了能被1和它本身整除外,不能被其它数所整除的数.判断一个自然数是否是素 ...

  6. leetcode8 字符串转换为整数

    最笨的办法实现 一步步判断 /** * @param {string} s * @return {number} */ var myAtoi = function(s) { s = s.trim() ...

  7. 【PHP】随机生成名字

    public function test(){ $a = "赵 钱 孙 李 周 吴 郑 王 冯 陈 楮 卫 蒋 沈 韩 杨 朱 秦 尤 许 何 吕 施 张 孔 曹 严 华 金 魏 陶 姜 戚 ...

  8. Matlab使用随记

    Matlab 2020 想要看图像每一点的值大小 工具--->数据提示 想要导出的分辨率提高 导出设置--->渲染--->600dpi Matlab 2017b 程序运行后,画出图, ...

  9. 虚拟机乌班图系统安装 VMware tools 工具

    在VMware虚拟机中安装完毕Linux操作系统之后,我们经常会发现桌面不能全屏显示或者windows主机系统与linux操作系统之间无法创建共享文件夹.这是因为我们还没有安装VMware tools ...

  10. Typescript, ES6

    * typescript 中文文档 https://www.tslang.cn/docs/home.html * ECMAScript 6 入门 http://es6.ruanyifeng.com/# ...