洛谷P1979华容道
此题目中存在三种棋盘的放置方法(空白,不能活动,能活动)。
而每次变化的格子一定在当前空白格子的周围,因此只需要对空白格子的周围四个状态考虑即可,因此我们设\(a[i][j][k]\)为白格子在(i,j)的k方向的一个状态,然后我们考虑,如果活动和不能活动的格子已经确定了,那么如果按照暴力的解法每次询问都需要对一开始的白格子向外扩展而得到的,这样会重复计算,因此我们可以快速计算出所有可移动的格子向周围移动所需要的时间,用\(dis[i][j][k][h]\)表示空格子在\((i,j)\)的\(k\)方向,然后\((i,j)\)跳到\((i+dx[h], j+dx[h])\)所需要的时间。这样就比较使状态表现的完全了,因为每次从一个格子移动到令一个格子时,就不需要用搜索来更新了,直接用此时间更新。
再向外扩展一下,则将状态抽象到图上的点,则原题就转化成了从起点到终点状态的最短路了。
对于每个询问,终点状态都有最多4个:
\(a[tx][ty][0/1/2/3]\)里面的任何满足条件且用时最短的的一个。
起点状态有4个,分别是\(a[sx][sy][0/1/2/3]\),但是此时白格子并没有到这四个方向上,因此我们用s表示一个不存在的节点,然后把这个节点跟起点的四个状态连边,边权分别是起始白格子位置到这四个方向的位置所用的时间。然后跑最短路就可以了
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int n, m, q, minn, ex, ey, sx, sy, tx, ty, cnt, tot, lin[1001001];
int dx[100] = {1, -1, 0, 0}, dy[100] = {0, 0, 1, -1};
int temp[1001][1001], vis[1001][1001], a[100][100][6];//a[i][j][0/1/2/3]分别表示(i,j)位置的空格子,方向为k时的状态编号
int dis[100][100][6][6];//空格子在(i,j)的k方向,然后i,j跳到(i+dx[h], j+dx[h])所需要的时间
struct dat {
int x, y, t;
};
struct edg {
int from, to, nex, len;
}e[1090100];
bool ch(int x, int y){if (x >= 1 && x <= n && y >= 1 && y <= m && temp[x][y]) return 1;return 0;}
inline void add(int f, int t, int l)
{
e[++cnt].to = t;
e[cnt].len = l;
e[cnt].from = f;
e[cnt].nex = lin[f];
lin[f] = cnt;
}
int bfs(int x, int y, int k, int h)//是白格子(x,y)到(k,h)的最小次数
{
queue <dat> q;
memset(vis, 0, sizeof(vis));
q.push({x, y, 0});
while ( !q.empty() )
{
dat now = q.front();
q.pop();
int wx = now.x, wy = now.y, wt = now.t;
if (wx == k && wy == h)
return wt;
for (int i = 0; i < 4; i++)
{
int nx = wx + dx[i], ny = wy + dy[i];
if (ch(nx, ny) && !vis[nx][ny])
q.push({nx, ny, wt + 1}), vis[nx][ny] = 1;
}
}
return inf;
}
inline void init()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
scanf("%d", &temp[i][j]);
for (int k = 0; k < 4; k++)
a[i][j][k] = ++tot;//tot表示状态编号,(i,j)的k方向上必须可以放置白色方块。
}
memset(dis, 0x3f, sizeof(dis));//最短路初始赋为最大值。
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (temp[i][j])
{
temp[i][j] = 0;//先将该点设为不能走,防止跟空格交换
memset(vis, 0, sizeof(vis));
for (int k = 0; k < 4; k++)
for (int h = 0; h < 4; h++)
if ( ch(i + dx[h], j + dy[h]) && ch(i + dx[k], j + dy[k]) )
{
if (h == k)
dis[i][j][k][h] = 1;
else dis[i][j][k][h] = bfs(i + dx[k], j + dy[k], i + dx[h], j + dy[h]) + 1;//最后还要进行一次交换为了转移白色方块。
printf("%d %d %d %d\n", i, j, k, h);
}
temp[i][j] = 1;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
for (int k = 0; k < 4; k++)
for (int h = 0; h < 4; h++)
if (dis[i][j][k][h] < 1061109567)
add(a[i][j][k], a[i + dx[h]][j + dy[h]][h ^ 1], dis[i][j][k][h]);//异或是表示当前转移格子的反方向。
}
int dp[1001101], inq[10010011];
void spfa(int s)
{
// memset(inq, 0, sizeof(vis));
memset(dp, 0x3f, sizeof(dp));
queue <int> q;
dp[s] = 0;
q.push(s);
while (!q.empty())
{
int cur = q.front();
q.pop();
inq[cur] = 0;
for (int i = lin[cur]; i; i = e[i].nex)
{
int to = e[i].to;
if (dp[to] > dp[cur] + e[i].len)
{
dp[to] = dp[cur] + e[i].len;
if (!inq[to])
inq[to] = 1, q.push(to);
}
}
}
}
int main()
{
init();
for (int i = 1; i <= q; i++)
{
scanf("%d%d%d%d%d%d", &ex, &ey, &sx, &sy, &tx, &ty);
if (sx == tx && sy == ty)
{
printf("0\n");
continue;
}
int s = ++tot;
int t = ++tot;
temp[sx][sy] = 0;
for (int i = 0; i < 4; i++)
if (ch(sx + dx[i], sy + dy[i]))
{
int ha = bfs(sx + dx[i], sy + dy[i], ex, ey);
if (ha < inf)
add(s, a[sx][sy][i], ha);//首先将白格子移到当前起点的周围,此时初始化的状态就有用了
}
temp[sx][sy] = 1;
for (int i = 0; i < 4; i++)
if (ch(tx + dx[i], ty + dy[i]))
add(a[tx][ty][i], t, 0);//到达此状态则就已经到达了终点了,因为白格子在终点的周围, 所以终点此时不是白格子,而是棋子。
spfa(s);
if (dp[t] == inf)
printf("-1\n");
else
printf("%d\n", dp[t]);
}
return 0;
}
洛谷P1979华容道的更多相关文章
- 洛谷 P1979 华容道 解题报告
P1979 华容道 题目描述 小\(B\)最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时 ...
- 洛谷P1979 华容道(70分 暴力)
P1979 华容道 题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少 ...
- [NOIP2013] 提高组 洛谷P1979 华容道
题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 ...
- 洛谷P1979 华容道
神の契约 题目大意:自己看去... 题解:做了一下午...本蒟蒻立志要写全网最详细的题解.╭(╯^╰)╮ begin.... 暴力70分.可以让空格子到处乱走,只要某个状态的指定格子到目标格子,那么此 ...
- 洛谷P1979 [NOIP2013提高组Day2T3]华容道
P1979 华容道 题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少 ...
- 洛谷 P1979 [ NOIP 2013 ] 华容道 —— bfs + 最短路
题目:https://www.luogu.org/problemnew/show/P1979 真是一道好题... 首先考虑暴力做法,应该是设 f[i][j][x][y] 记录指定棋子和空格的位置,然后 ...
- 洛谷 1979 华容道——最短路+dp
题目:https://www.luogu.org/problemnew/show/P1979 感到无从下手.但不妨用dp的角度来看.因为空格只有在指定棋子的旁边才有用,所以状态记成制定棋子的位置与空格 ...
- [NOIP2013 提高组] 华容道 P1979 洛谷
[NOIP2013 提高组] 华容道 P1979 洛谷 强烈推荐,更好的阅读体验 经典题目:spfa+bfs+转化 题目大意: 给出一个01网格图,和点坐标x,y空格坐标a,b,目标位置tx,ty要求 ...
- 洛谷1640 bzoj1854游戏 匈牙利就是又短又快
bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...
随机推荐
- js图片压缩+ajax上传
图片压缩用到了localresizeimg 地址: https://github.com/think2011/localResizeIMG 用起来比较简单 <input type="f ...
- quota - linux磁盘配额管理
磁盘管理系列 linux磁盘管理系列一:磁盘配额管理 http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_linux_040_quota.html l ...
- 2019 美柚java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.美柚等公司offer,岗位是Java后端开发,因为发展原因最终选择去了美柚,入职一年时间了,也成为了面试官,之 ...
- SQLI-LABS LESS 1-LESS 22
SQLI-LABS LESS 1-LESS 22 0x01:前言 因为最近感觉手注快忘光了,所以玩一遍sqli-labs巩固一下. sql注入,基于从服务器接收到的响应分类为 : ▲基于错误的SQL注 ...
- XenServer Tools安装
右键Linux虚拟机,选择 Install XenServer Tools XenCenter 切换到 Console界面 执行如下命令安装: # mount /dev/xvdd /mnt # /mn ...
- git 检索
图形化客户端:sourcetree下载: https://www.sourcetreeapp.com/安装: 由于种种不可描述的原因,无法注册账号且无法登陆所以需要绕过登陆绕过登陆: 去到 C:\Us ...
- 虚拟机-VMware小结
1.网卡的3种模式 桥接模式:虚拟机=物理机器,连接物理网卡,虚拟ip设置物理网卡的网段和网管.可上网. NAT模式:虚拟机把物理机器当做路由器,虚拟ip网段ip自动获取.可上网. https://w ...
- 设计模式之动态代理(JDK代理)
动态代理跟静态代理一个很重要的区别在于,动态代理是在内存是中的,是在代码编译期后在内存是实现的,而静态代理是我们自己编写代理类,编译后生成class文件.动态代理需要借助两个类:java.lang.r ...
- Laravel - Method [xxx] does not exist on [xxx]
The controller is existing, and the method 'test' exist on 'App\Http\Controllers\Admin\IndexControll ...
- scrapy框架之代理的使用
首先我们检测ip是否可用: 1.对于免费代理的检测 #免费代理或不用密码的代理 url = 'http://httpbin.org/get' proxy = '127.0.0.0:8000' prox ...