洛谷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炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...
随机推荐
- NETCore执行Shell修改Centos系统IP信息
原文:NETCore执行Shell修改Centos系统IP信息 目录 shell代码 NETCore执行Shell文件 注意事项 shell代码 首先通过find命令找到/etc/sysconfig/ ...
- 一款比较强大的jquery表格插件Datatables
Datatables是一款jquery表格插件.它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能. 链接:http://www.datatables.club/ 本人无聊时发现的一款用 ...
- C# 查看系统进程
//使用前需要引用 using System.Diagnostics; var processList = Process.GetProcesses().ToList();
- HTML5 表单新增内容
一.H5 新增控件 1.datalist 元素 datalist 标签定义选项列表,请与 input 元素配合使用该元素.可为输入框提供一个可选的列表,可以直接选择列表项,也可以不选择列表中的项,自行 ...
- setsockopt()函数使用
closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket BOOL bReuseaddr=TRUE; setsockopt (s,SOL_SOCKET ,SO ...
- Samba + DLAN 实现电视机播放电脑文件
用SMB功能——简单二步让电视访问电脑文件http://tieba.baidu.com/p/5330683066 DLNA怎么用?简单三步实现电脑电视DLNA互联!https://news.znds. ...
- Java 7 NIO.2学习(Ing)
Path类 1.Path的基本用法 Path代表文件系统中的位置,即文件的逻辑路径,并不代表物理路径,程序运行的时候JVM会把Path(逻辑路径)对应到运行时的物理位置上. package com.j ...
- Java集合学习(4):HashTable
一.概述 和HashMap一样,Hashtable也是一个散列表,它存储的内容是键值对. Hashtable在Java中的定义为: public class Hashtable<K,V> ...
- AES加密解密工具类封装(AESUtil)
package club.codeapes.common.utils; import org.springframework.util.Base64Utils; import javax.crypto ...
- jmeter使用小结
写这篇短文主要想详细介绍一下jmeter中取样器.逻辑控制器.前置处理器.后置处理器.定时器.配置元件等,可能看起来比较繁杂,其实里面很多操作是类似的,一篇总结和记录的博客: jmeter官方用户手册 ...