重力球

题目链接:luogu P7473

题目大意

有一个图中有一些障碍物,边界也是障碍物。
然后又每个询问给出两个小球的位置,你可以改变重力变成左右前后,问你最少要改变多少次重力才能使得两个小球滚到一起。
如果不能滚到一起输出 -1,多组询问。

思路

因为是根据重力,那在一次滚动之后,这个点停留在那里一定是因为有障碍物挡住了它,那也就说,有效的点就是旁边四个方向有障碍物的点。

那可以根据数据算出点最多不超过 200020002000 个。
那我们可以先看看一个询问怎么弄,那因为我们把点压缩到这么小,所以我们可以直接暴搜。
(不过要先自己模拟一步走到关键点)

当然,我们可以先通过一个简单的 DP 算出一个点往四个方向走可以到哪里。
就如果那个方向走一步是障碍物,那就只能走到自己,否则就在走到的地方往那个方向继续走。
然后用合适的顺序可以直接不用继续走,因为当时已经算出了答案。

但是它是多组询问,而且询问还挺多,10510^5105 个。
基本上明摆着要直接预处理出所有答案。

你考虑反过来想,你枚举最终会和的地方,然后看可以从那两个位置走到。
那你把每个会和的地方放进队列里面进行 bfs,每次就选一个方向,然后从可以走过来的地方各选一个转移。
那就是反向建边。
然后你就可以这样搜出两个关键点会和所要的最少步数。

那你就根据上面的一样,先走一步使两个都到关键点,然后就可以把四个方向得出的距离取最小值。
那你会想,如果它一步都不走呢?
那就是一开始就在同一个位置,特判一下就好。

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>using namespace std;struct node {int to, nxt;
}e[100001];
struct state {int x, y;
};
queue <state> q;
int le[2001][4], KK, tmp;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
int n, m, Q, x, y, tot, px[2001], py[2001];
int pl[251][251], go[251][251][4][2];
int dis[2001][2001], ans;
int x1, y1, x2, y2;bool ck(int x, int y) {if (pl[x][y] == -1) return 0;if (x < 1 || x > n) return 0;if (y < 1 || y > n) return 0;return 1;
}void add(int x, int y, int way) {//因为你要每次走的方向一样,所以 head 要开四个分开记录四个方向的swap(x, y);//记得是反向建边e[++KK] = (node){y, le[x][way]}; le[x][way] = KK;
}void bfs() {//bfs 暴搜for (int i = 1; i <= tot; i++)q.push((state){i, i}), dis[i][i] = 1;//一开始要走一步才能走到关键点while (!q.empty()) {state now = q.front();q.pop();x = now.x;y = now.y;for (int k = 0; k < 4; k++)//每次走的方向要一样for (int i = le[x][k]; i; i = e[i].nxt)for (int j = le[y][k]; j; j = e[j].nxt)if (dis[e[i].to][e[j].to] == tmp)q.push((state){e[i].to, e[j].to}), dis[e[i].to][e[j].to] = dis[x][y] + 1;}
}int main() {scanf("%d %d %d", &n, &m, &Q);for (int i = 1; i <= m; i++) {scanf("%d %d", &x, &y);pl[x][y] = -1;}for (int i = 1; i <= n; i++)pl[0][i] = pl[n + 1][i] = pl[i][0] = pl[i][n + 1] = -1;for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)if (pl[i][j] != -1) {for (int k = 0; k < 4; k++)if (pl[i + dx[k]][j + dy[k]] == -1) {pl[i][j] = ++tot;//给有需要的位置编号break;}}for (int i = 1; i <= n; i++)//DP 出四个方向可以走到哪里for (int j = 1; j <= n; j++)if (ck(i, j)) {if (ck(i + dx[2], j + dy[2]))go[i][j][2][0] = go[i + dx[2]][j + dy[2]][2][0], go[i][j][2][1] = go[i + dx[2]][j + dy[2]][2][1];else go[i][j][2][0] = i, go[i][j][2][1] = j;if (ck(i + dx[3], j + dy[3]))go[i][j][3][0] = go[i + dx[3]][j + dy[3]][3][0], go[i][j][3][1] = go[i + dx[3]][j + dy[3]][3][1];else go[i][j][3][0] = i, go[i][j][3][1] = j;}for (int i = n; i >= 1; i--)for (int j = n; j >= 1; j--)if (ck(i, j)) {if (ck(i + dx[0], j + dy[0]))go[i][j][0][0] = go[i + dx[0]][j + dy[0]][0][0], go[i][j][0][1] = go[i + dx[0]][j + dy[0]][0][1];else go[i][j][0][0] = i, go[i][j][0][1] = j;if (ck(i + dx[1], j + dy[1]))go[i][j][1][0] = go[i + dx[1]][j + dy[1]][1][0], go[i][j][1][1] = go[i + dx[1]][j + dy[1]][1][1];else go[i][j][1][0] = i, go[i][j][1][1] = j;}for (int i = 1; i <= n; i++)//建边for (int j = 1; j <= n; j++)if (pl[i][j] > 0)for (int k = 0; k < 4; k++)add(pl[i][j], pl[go[i][j][k][0]][go[i][j][k][1]], k);memset(dis, 0x7f, sizeof(dis));tmp = dis[0][0];bfs();while (Q--) {scanf("%d %d %d %d", &x1, &y1, &x2, &y2);if (x1 == x2 && y1 == y2) {//一开始就在用一个位置printf("0\n");continue;}ans = tmp;for (int i = 0; i < 4; i++)//一开始选一个方向走到关键点ans = min(ans, dis[pl[go[x1][y1][i][0]][go[x1][y1][i][1]]][pl[go[x2][y2][i][0]][go[x2][y2][i][1]]]); if (ans == tmp) {printf("-1\n");}else printf("%d\n", ans);}return 0;
}

【luogu P7473】重力球相关推荐

  1. Cocos Creator 一步一步实现重力球游戏

    「获取源码」 点击上方蓝字关注公众号「游戏开发小白变怪兽」,回复「重力球」获取源码及美术资源. 「游戏玩法」 通过手机陀螺仪,调整手机,让球从上一层的间隔中落到下一层,楼层会不断上涨,如果球碰到上方或 ...

  2. js重力球效果代码实例

    分享一段代码实例,它利用js实现了重力球效果. 本例子中,用鼠标向下拖动小球,然后松开即可查看演示. 代码实例如下: 001 002 003 004 005 006 007 008 009 010 0 ...

  3. CocosCreator一步一步实现重力球游戏

    『 获取源码 』 关注公众号,发送"重力球"获取源码 『 游戏玩法 』 通过手机陀螺仪,调整手机,让球从上一层的间隔中落到下一层,楼层会不断上涨,如果球碰到上方或者下方的火焰,游戏 ...

  4. java字符下落,重力球,加速下落减速上弹,重力下落,这段代码是看到网上一个关...

    重力球,加速下落减速上弹,重力下落,这段代码是看到网上一个关 这段代码是看到网上一个关于碰壁球修改而成的,用到事件,画图,Timer类package Cheman;import javax.swing ...

  5. 【bfs】重力球(luogu 7473/NOI Online 2021 普及组 T3)

    正题 luogu 7473 题目大意 给出一个正方形区域,中间有一些障碍 现在有两个球,每次操作可以使两个球同时向一个方向移动,直到遇到障碍或边界 现在问你让两个球到同一个位置最少要多少步 解题思路 ...

  6. Cocos Creator下JavaScript一步一步实现重力球游戏,附代码

    『 游戏玩法 』 通过手机陀螺仪,调整手机,让球从上一层的间隔中落到下一层,楼层会不断上涨,如果球碰到上方或者下方的火焰,游戏结束. 『 游戏预览 』 『 开发工具 』 1. CocosCreator ...

  7. Cocos Creator一步一步实现重力球游戏,附完整代码

    『 游戏玩法 』 通过手机陀螺仪,调整手机,让球从上一层的间隔中落到下一层,楼层会不断上涨,如果球碰到上方或者下方的火焰,游戏结束. 『 游戏预览 』 『 开发工具 』 1. CocosCreator ...

  8. Cocos Creator 重力球游戏制作教程

    本文首发于:一枚小工(caizj_cn) Cocos 经授权转载,感谢作者创作 游戏玩法 通过手机陀螺仪,调整手机,让球从上一层的间隔中落到下一层,楼层会不断上涨,如果球碰到上方或者下方的火焰,游戏结 ...

  9. 重力球——重力感应器应用

    首届 Google 暑期大学生博客分享大赛--2010 Andriod 篇 之前在网上看到一个HTC的Windows Mobile手机中的一个应用重力感应器的程序"蛋疼的小球",地 ...

最新文章

  1. mybatis创建oracle用户,搭建Mybatis+Oracle项目以及简单的增删改查语法
  2. C/C++中volatile关键字详解
  3. php中border属性,css中display属性和border属性常遇问题讲解
  4. IOS 程序插件及功能动态更新思路┊
  5. jquery的$F()函数
  6. Java中继承thread类与实现Runnable接口的区别
  7. 认识计算机ppt课件游戏,《认识计算机》PPT课件
  8. SSH框架整合——基于注解
  9. (44)Xilinx ROM IP核配置(五)(第9天)
  10. 【文献阅读】Augmenting Supervised Neural Networks with Unsupervised Objectives-ICML-2016
  11. 利用 Python 预测英雄联盟胜负,分析了 5 万多场比赛才得出的数据!
  12. ABTest灰度发布
  13. 使用XML及XSL生成简单HTML
  14. 计算机视觉基础:图像处理 Task 03 - 颜色空间互转
  15. MySql update inner join!MySql跨表更新 多表update sql语句?如何将select出来的部分数据update到另一个表里面?...
  16. 《Arduino奇妙之旅:智能车趣味制作天龙八步》一1.6 A计划
  17. 社交媒体与社会网络分析,深度解读社交网络营销
  18. MYSQL判断中文、英文、日文常用语句
  19. python入门教程(非常详细),python基础教程 入门教程
  20. 如何求置换奇偶性、对换乘积

热门文章

  1. 什么是CUSDEC 报关单?
  2. 太划算了! 1 元秒杀 1000 本爆款电子书!
  3. chrome浏览器导出文件提示病毒扫描失败
  4. js实现幻灯片效果二
  5. html实现ppt的效果,js、css实现ppt的出现效果
  6. C#泛型List 的定义、作用、用法
  7. 星际争霸等待暴雪服务器响应,服务器三个月未恢复正常,垂死挣扎的星际争霸,预示着傲慢的暴雪即将谢幕...
  8. 计算机虚拟化技术的未来前景,计算机虚拟化技术及应用前景分析
  9. Linux网络编程——Unix本地套接字
  10. 离线win7上用anaconda离线创建虚拟环境