【NOIP2013】华容道
看别人的代码然后被坑了一下午+一晚上,睡一觉第二天醒悟过来打表过了
果然打表才是正确的调试方法,跟踪什么的去屎(╯‵□′)╯︵┻━┻
原题:
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1 个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
2. 有些棋子是固定的,有些棋子则是可以移动的;
3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。
游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。
给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EX[i] 行第 EY[i] 列,指定的可移动棋子的初始位置为第 SX[i] 行第 SY[i] 列,目标位置为第 TX[i] 行第 TY[i] 列。
假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请
你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。
1 ≤ n, m ≤ 30,q ≤ 500。
这题暴力分很实惠,很容易写出一个bfs能拿到60-70
想要A掉怎么办呐
正解就要魔性p♂l♀a♂y了
用一个状态b[i][j][k][h]表示第i行第j列的格子,空格在k方向,这个格子要移动到h方向需要的最小步数
这个步数怎么求呐
可以用一个bfs,求出空格从k方向到h方向需要的步数,然后需要移动的格子和h方向的空格交换即可,可以证明这样做是最优的(逃
然后一个三维的点c[i][j][k]表示第i行第j列的格子,空格在k方向,上面用bfs求出步数↑后就可以把c[i][j][k]与c[i+k方向上x的变化量][j+k方向上y的变化量][h的反方向]连上权值为步数的边
因为求出步数的方法是先把空格移到h方向,在把格子和空格交换↑,所以边的汇点的方向是h的反方向
然后每次询问的时候,可以直接套用上面的bfs↑求出把空白格移动到要移动的方格附近需要的步数,四个方向都搞一下,建一个源点s,把s与c[i][j][k]连上权值为步数的边
然后再建一个汇点t,把t和c[目标节点x][目标节点y][四个方向]连上权值为0的边
然后就可以开心地搞最短路辣
需要注意的的方:
最好判断一下要移动的格子和目标格子是一个东西以及要移动的格子或目标格子不合法的情况
连边的时候需要注意什么时候坐标要加上方向,什么时候坐标是原格子
小技巧:
可以用一个计数,在输入数据的时候给每个c[i][j][k]都标上号,连边的时候就很方便
把x和y的变化量分别设成{1,-1,0,0},{0,0,1,-1},这样直接用k^1就可以快速取到反向边
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int oo=;
int fx[]={,-,,},fy[]={,,,-};
struct ddd{int next,y,value;}e[];int LINK[],ltop=;
inline void insert(int x,int y,int z){e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;e[ltop].value=z;}
int m,n,q,a[][];
int hash[][][],hash_cnt=;
int dui[],tou=;
int bf[][];
int s,t;
int sf[];
bool visited[];
int bfs(int sx,int sy,int tx,int ty){
memset(bf,,sizeof(bf));
dui[tou=]=(sx-)*n+sy-; bf[sx][sy]=;
for(int k=;k<=tou;k++){
int x=dui[k]/n+,y=dui[k]%n+;
for(int i=;i<;i++)if(a[x+fx[i]][y+fy[i]] && bf[x+fx[i]][y+fy[i]]>bf[x][y]+){
bf[x+fx[i]][y+fy[i]]=bf[x][y]+;
//if(x+fx[i]==tx && y+fy[i]==ty) return bf[tx][ty];
dui[++tou]=(x+fx[i]-)*n+y+fy[i]-;
}
}
return bf[tx][ty];
}
int spfa(){
memset(sf,,sizeof(sf));
memset(visited,,sizeof(visited));
dui[tou=]=s; sf[s]=;
for(int k=;k<=tou;k++){
visited[dui[k]]=false;
for(int i=LINK[dui[k]];i;i=e[i].next)
if(sf[e[i].y]>sf[dui[k]]+e[i].value){
sf[e[i].y]=sf[dui[k]]+e[i].value;
if(!visited[e[i].y]) dui[++tou]=e[i].y,visited[e[i].y]=true;
}
}
return (sf[t]<oo) ? sf[t] : -;
}
int main(){//freopen("ddd.in","r",stdin);
cin>>m>>n>>q;
for(int i=;i<=m;i++) for(int j=;j<=n;j++){
scanf("%d",&a[i][j]);
for(int k=;k<;k++) hash[i][j][k]=++hash_cnt;
}
for(int i=;i<=m;i++)
for(int j=;j<=n;j++)if(a[i][j])
for(int k=;k<;k++)if(a[i+fx[k]][j+fy[k]]){
insert(hash[i][j][k],hash[i+fx[k]][j+fy[k]][k^],);
//cout<<i<<" "<<j<<" "<<k<<" "<<i+fx[k]<<" "<<j+fy[k]<<" "<<(k^1)<<" "<<1<<endl;
for(int q=;q<;q++)if(q!=k && a[i+fx[q]][j+fy[q]]){
a[i][j]=;
int bu=bfs(i+fx[k],j+fy[k],i+fx[q],j+fy[q])+;
if(bu<oo){ insert(hash[i][j][k],hash[i+fx[q]][j+fy[q]][q^],bu); /*cout<<i<<" "<<j<<" "<<k<<" "<<i+fx[q]<<" "<<j+fy[q]<<" "<<(q^1)<<" "<<bu<<endl;*/}
a[i][j]=;
}
}
int sx,sy,tx,ty,kx,ky;
while(q --> ){//趋向于
scanf("%d%d%d%d%d%d",&kx,&ky,&sx,&sy,&tx,&ty);
if(sx==tx && sy==ty){ printf("0\n"); continue;}
if(!a[sx][sy] || !a[tx][ty]){ printf("-1\n"); continue;}
s=++hash_cnt;t=++hash_cnt;
a[sx][sy]=;
for(int k=;k<;k++)if(a[sx+fx[k]][sy+fy[k]]){
int bu=bfs(kx,ky,sx+fx[k],sy+fy[k]);
if(bu<oo) insert(s,hash[sx][sy][k],bu);
}
a[sx][sy]=;
for(int k=;k<;k++)if(a[tx+fx[k]][ty+fy[k]])
insert(hash[tx][ty][k],t,);
printf("%d ",spfa());
}
return ;
}
【NOIP2013】华容道的更多相关文章
- LOJ2613 NOIP2013 华容道 【最短路】*
LOJ2613 NOIP2013 华容道 LINK 这是个好题,具体题意比较麻烦可以直接看LINK中的链接 然后考虑我们可能的移动方式 首先我们需要把白块移动到需要移动块S的附近(附近四格) 然后我们 ...
- [NOIP2013]华容道 题解(搜索)
[NOIP2013]华容道 [题目描述] 这道题根据小时候玩华容道不靠谱的经验还以为是并查集,果断扑街.考后想想也是,数据这么小一定有他的道理. 首先由于是最小步数,所以BFS没跑了.那么我们大可把这 ...
- [NOIP2013]华容道 题解
[NOIP2013]华容道 首先是一种比较显然的做法. 整个棋盘,除了起点,终点和空格,其他的方块是等价的. 对于终点,它始终不会变化,如果搜到终点结束搜索即可,所以我们不需要考虑终点. 所以需要考虑 ...
- [NOIP2013]华容道
1.题面 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间.小 B 玩的华容道与经典 ...
- noip2013华容道
题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 ...
- NOIP2013 华容道 (棋盘建图+spfa最短路)
#include <cstdio> #include <algorithm> #include <cstring> #include <queue> # ...
- NOIP2013华容道 大爆搜
预处理出每个点周围四个点互相到达的最短路,再在整个图上跑SPFA,要记录路径 #include<cstdio> #include<cstring> #include<io ...
- NOIP2013华容道(BFS+乱搞)
n<=30 * m<=30 的地图上,0表示墙壁,1表示可以放箱子的空地.q<=500次询问,每次问:当空地上唯一没有放箱子的空格子在(ex,ey)时,把位于(sx,sy)的箱子移动 ...
- luogu P1979 [NOIP2013] 华容道
传送门 这道题中,棋子的移动是要移动到空格上去,所以空格要在棋子旁边才能移动棋子;而棋子移动的方向由空格决定 所以我们可以记三维状态\(di_{i,j,k}\),表示状态为棋子在\((i,j)\),空 ...
- [Luogu1979][NOIP2013]华容道(BFS+SPFA)
考虑从起点到终点的过程,一定是先将空格子移到指定格子旁边,和指定格子交换,再移到下一个指定格子要到的地方,再交换,如此反复. 于是问题分为两个部分: 1.给定两个曼哈顿距离为2的格子求最短路,BFS即 ...
随机推荐
- scrollView自动加载数据demo
package combaidu.mylistsrollview; import java.util.ArrayList;import java.util.List; import com.baidu ...
- redis——基础介绍
转自:http://www.cnblogs.com/xing901022/p/4863929.html 1 什么是Redis Redis(REmote DIctionary Server,远程数据字典 ...
- Mvc5 Html.EditorFor
如果对缺省的样子不满意, 可以有模板,寻寻觅觅,摸索出 在Views\Shared\EditorTemplates下创建String.cshtml 必须的是EditorTemplates文件夹 @{ ...
- lib静态链接库,dll动态链接库,h文件
最近在弄摄像头,发现我在调用摄像头自带的函数的时候,库没连接上,于是经过高人指点,学习了一下lib静态链接库,dll动态链接库来补充一下自己的基础知识. 一.首先我们来介绍一下lib静态链接库. li ...
- ZOJ 2672 Fibonacci Subsequence(动态规划+hash)
题意:在给定的数组里,寻找一个最长的序列,满足ai-2+ai-1=ai.并输出这个序列. 很容易想到一个DP方程 dp[i][j]=max(dp[k][i])+1. (a[k]+a[i]==a[j], ...
- Tab切换栏
// Tab切换栏 function setTab(name, m, n) { for (var i = 1; i <= n; i++) { var menu = document.getEle ...
- TCP协议三次握手过程分析【图解,简单清晰】
转自:http://www.cnblogs.com/rootq/articles/1377355.html TCP(Transmission Control Protocol) 传输控制协议 TCP是 ...
- C# 调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配
在dllimport中加入CallingConvention参数就行了,[DllImport(PCAP_DLL, CharSet = CharSet.Auto, CallingConvention = ...
- PHP的循环结构
循环结构一.while循环 while循环是先判断条件,成立则执行 使用一个while循环输出的表格 <style type="text/css"> td{ te ...
- ERP权限系统(七)
添加链接权限的字段: //权限管理 n.Target = "MainFrame"; //折叠 TreeView1.Nodes.Add(n); n.Expanded = false;