首页 > 其他分享 >洛谷 P7473 [NOI Online 2021 入门组] 重力球

洛谷 P7473 [NOI Online 2021 入门组] 重力球

时间:2022-11-11 21:59:11浏览次数:78  
标签:const point int P7473 d% return bfs 2021 洛谷

题面

题目链接

题解

首先这题放在图论专题难度就下降了一大个档次ww

我们注意到一点,就是如果你可以把两个点的位置记下来,一步操作之后,只会有四种可能的情况.

两个点的位置情况乍一看是 \(n^4\approx 3.9\times10^9\) 存不下,但是注意到一步操作之后,一定会在障碍点四周四个点或者边界上.

所以情况数只有 \((4m+4n)^2=4\times10^6\),完全可以接受.

然后我们的思路就是先预处理出所有点移动一步可能的位置,建图,bfs 求出每个点最小的步数,然后回答询问的时候枚举一下第一步的情况.

小常识:边权为1的图的最短路可以用bfs \(O(n)\) 求

到多个点的最小步数直接把所有终点塞进去bfs就好了

时间复杂度 \(O((4m+4n)^2+q)\)

呃这个代码实现不太好写(我的码力问题

实现上的小细节

记得建的是反边,回答询问的时候记得特判两个点最开始是否已经重合.

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 255, M = 4e6+5, inf = 1e9;
int n,m,q,np;
struct point 
{ 
	int x,y;
	void rd() { scanf("%d%d",&x,&y); }
	void print() { printf("(%d,%d)",x,y); }
	friend bool operator< (const point &a, const point &b) { return a.x<b.x or (a.x==b.x and a.y<b.y); }
	friend bool operator== (const point &a, const point &b) {return a.x==b.x and a.y==b.y; } 
	friend point operator+ (const point &a, const point &b) { return {a.x+b.x,a.y+b.y}; } 
	friend point operator- (const point &a, const point &b) { return {a.x-b.x,a.y-b.y}; } 
} p[N<<3];

int a[N][N][4],dis[M],mp[N][N];
inline int p_to_q(int x, int y) { return (x-1)*np+y; }
int head[M],nxt[M<<4],ver[M<<4],tot;
void add(int x, int y) { ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot; }

void init()
{
	//init p
	static point obs[N],dir[]={{1,0},{0,1},{-1,0},{0,-1}};
	static int vt[N][N];
	auto check=[&](point t) { return 1<=t.x and t.x<=n and 1<=t.y and t.y<=n and !vt[t.x][t.y]; };
	for(int i=1; i<=m; i++) obs[i].rd(),vt[obs[i].x][obs[i].y]=1;
	for(int i=1; i<=n; i++)
	{
		if(check({1,i})) p[++np]={1,i};
		if(check({n,i})) p[++np]={n,i};
		if(check({i,1})) p[++np]={i,1};
		if(check({i,n})) p[++np]={i,n};
	}
	for(int i=1; i<=m; i++) for(int j=0; j<4; j++)
	{
		point t=obs[i]+dir[j];
		if(check(t)) p[++np]=t;
	}
	sort(p+1,p+np+1); np=unique(p+1,p+np+1)-p-1;
	for(int i=1; i<=np; i++) mp[p[i].x][p[i].y]=i;
	//init a
	for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) 
		if(check({i,j})) for(int k=0; k<4; k++)
		{
			point c={i,j};
			while(check(c+dir[k])) c=c+dir[k];
			a[i][j][k]=mp[c.x][c.y];
		}
	//init q
	for(int i=1; i<=np; i++) for(int j=1; j<=np; j++)
		for(int k=0; k<4; k++)
		{
			int u=p_to_q(i,j); 
			int v=p_to_q(a[p[i].x][p[i].y][k],a[p[j].x][p[j].y][k]);
			add(v,u);
		}
}
void work_dist()
{
	queue<int> q;
	static int vis[M];
	for(int i=1; i<=np*np; i++) dis[i]=inf;
	for(int i=1; i<=np; i++) { int t=p_to_q(i,i); q.push(t); dis[t]=0; vis[t]=1; }
	while(!q.empty())
	{
		int u=q.front(); q.pop();
		for(int j=head[u]; j; j=nxt[j])
		{
			int v=ver[j]; 
			if(!vis[v]) dis[v]=min(dis[v],dis[u]+1),vis[v]=1,q.push(v);
		}
	}
}
void answer_query()
{
	point S,T;
	while(q--)
	{
		S.rd(); T.rd(); int res=inf;
		if(S==T) res=0;
		else if(mp[S.x][S.y] and mp[T.x][T.y]) res=dis[p_to_q(mp[S.x][S.y],mp[T.x][T.y])];
		else for(int j=0; j<4; j++) res=min(res,1+dis[p_to_q(a[S.x][S.y][j],a[T.x][T.y][j])]);
		printf("%d\n",res>=inf?-1:res);
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	init(); work_dist(); answer_query();
	return 0;
}

标签:const,point,int,P7473,d%,return,bfs,2021,洛谷
From: https://www.cnblogs.com/copper-carbonate/p/16882123.html

相关文章

  • 【框架】984- 2021 年最佳 JavaScript 框架
    作者|OliviaCuthbert译者|Sambodhi策划|刘燕据Stackoverflow的2021年开发者调查,JavaScript已连续第八年成为使用最多的语言,有67.7%的受访者选择它。之所以如......
  • 洛谷-3131
    洛谷-3131思路首先有一个\(brute-force\),从大到小枚举区间长度,然后通过前缀和找是否存在这样的区间,时间复杂度\(o(n^2)\)。在上述操作中,实际上我们做的就是找到两个下标......
  • 洛谷-4552
    洛谷-4552思路首先需要由区间加减法或者最后的形式(变为1个数)联想到差分在差分的形式下,只剩一个数意味着差分数组中\(2\dotsn\)都必须为0,其他任意。而给我们的操作......
  • 洛谷刷题_质数口袋
    P5723【深基4.例13】质数口袋题目链接:https://www.luogu.com.cn/problem/P5723知识点:埃氏筛原理:要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数筛掉,......
  • AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码
    目录AIR32F103(一)合宙AIR32F103CBT6开发板上手报告AIR32F103(二)Linux环境和LibOpenCM3项目模板AIR32F103(三)Linux环境基于标准外设库的项目模板AIR32F103(四)2......
  • 洛谷1923 排序
    洛谷1923错误这道题用的快排,但是非常卡时间,最后将快排优化,新学stl中nth_element(数组名,数组名+第k小元素,数组名+元素个数);将第k小元素找出,最后直接输出就行//判断k......
  • 洛谷B2079求出e的值
    解题思路:注意变量的类型就ok了,没什么不容易理解的地方#include<stdio.h>intmain(){doublenum=1,sum=1;longlongb=1,n;scanf("%d",&n);for(inti=1;i<=n......
  • P7737 [NOI2021] 庆典
    题意给定一张有向图,每次询问给出\(s,t\),求从\(s\tot\)的路径上(可以有重复点)可能会经过多少个点,每次询问会临时加入\(k\)条边。其中,题目给出的图有如下特点:若\(x\)......
  • 洛谷 P4423 [BJWC2011]最小三角形 题解
    求平面最近点对的时候有这样一种思路:将所有点全部绕原点旋转同一个角度,然后按横坐标排序。根据数学直觉,在随机旋转后,答案中的两个点在数组中肯定不会离得太远。把这种......
  • 【408】2021
    t4给的序列是二叉树的。。而不是森林的t5带权路径长度乘的应该是路径长度才对,而不是树高t22额,中断这块还是糊里糊涂的t38建立TCP连接(SYN,SYN/ACK,ACK)释放TC......