洛谷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炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...
随机推荐
- asp.net core 系列之允许跨域访问-1(Enable Cross-Origin Requests:CORS)
接上篇的允许跨域 4.CORS 策略(Policy)的选项 这里讲解Policy可以设置的选项: 设置允许的访问源 设置允许的HTTP methods 设置允许的请求头(request header) ...
- C语言----循环结构1(基础篇五)
今天更新一个C语言的循环,简单点就是就是我们平时在使用电脑时不停的刷新网页,生活中每天都要吃饭等等就是循环,而编程中也有不断循环的过程,或者遇到符合的条件结束循环 下面进入今天的主题: 需求:用计算机 ...
- 创建你自己定制的vuejs plugin扩展app的功能
什么是vuejs plugin插件 vuejs plugin插件是一个向你的app注入新的全局功能的强大但又简约的方式.从概念上来说,vue plugin非常简单,它就是一个包含了install方法的 ...
- 八.软件自动化和web测试
1.软件自动化测试 1.1 自动化测试的概念 自动化测试:就是通过测试工具或其他手段,按照测试工程师的预定计划对软件产品进行自动化的测试 软件测试自动化涉及到测试流程.测试体系.自动化编译以 ...
- C# 查看系统进程
//使用前需要引用 using System.Diagnostics; var processList = Process.GetProcesses().ToList();
- idea中从代码自动定位到左侧类结构位置
标题的意思表达的不是很清楚,下面是这个设置的方法: 图中红圈中就是设置的位置,把鼠标悬浮在上面,可以看到这个设置的名称是Autoscroll from source, 它的作用是,你在代码中点击一个方 ...
- ES6 之 对象的简写方式
简写有两条基本原则: 同名的属性可以省略不写 对象中的方法中的 : function 可以省略不写 来看下下面这个例子,我分别用ES5 和 ES6 的语法分别定义并声明了一个简单的学生对象: ES5: ...
- python学习之:序列类型 之列表,元组,range
列表 列表是可变序列,通常用于存放同类项目的集合(其中精确的相似程度将根据应用而变化). class list([iterable]) 可以用多种方式构建列表: 使用一对方括号来表示空列表: [ ] ...
- kbmmw 5.10.10 发布
这个版本主要是bug修正. New stuff ========= - Added OnException event property to TkbmMWSchedu ...
- 基于Chrominum的发行版本Microsoft Edge-Beta
问题描述: Microsoft Edge -->Chromium Edge(未来Window的主力浏览器) 问题解决: 下载地址: https://www.microsoftedgeinside ...