BZOJ 1967 Ahoi2005 CROSS 穿越磁场 FloodFill+BFS

本文详细介绍了如何通过离散化、Floodfill算法标记区域以及BFS寻找两点间最少穿越的边界数。适用于平面内n个正方形场景,通过实例分析并提供代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:给定平面上的n个正方形,求某个点到另一个点至少穿过多少个边界

一开始想对于每个正方形判断一下起点和终点是否在同一侧= = 但是反例显然

考虑到n<=100,可以离散化一下,然后用Floodfill标记每块区域

然后跑最短路就行了……由于边权都是1,所以用BFS就能搞出最短路了

连边连挂了调了半宿……

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 310
using namespace std;
struct abcd{
	int x,y,c;
	friend istream& operator >> (istream &_,abcd &a)
	{
		scanf("%d%d%d",&a.x,&a.y,&a.c);
		return _;
	}
}a[M];
struct Rectangle{
	int x1,x2,y1,y2;
}rectangles[M];
struct edge{
	int to,next;
}table[500500];
int head[M*M],tot;
int m=1,n=1,cnt,T;
int xa,ya,xb,yb,map[M][M],f[100100];
pair<int,int*> b[M];
bool map1[M][M],map2[M][M];
void Add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void Floodfill(int x,int y)
{
	
	int xx,yy;
	
	map[x][y]=T;

	xx=x,yy=y-1;
	if( !map1[x][y] )
	{
		if( y!=1 && !map[xx][yy] )
			Floodfill(xx,yy);
	}
	else if(map[xx][yy])
		Add(T,map[xx][yy]),Add(map[xx][yy],T);
		
	xx=x,yy=y+1;
	if( !map1[x][y+1] )
	{
		if( y!=n && !map[xx][yy] )
			Floodfill(xx,yy);
	}
	else if(map[xx][yy])
		Add(T,map[xx][yy]),Add(map[xx][yy],T);
		
	xx=x-1,yy=y;
	if( !map2[x][y] )
	{
		if( x!=1 && !map[xx][yy] )
			Floodfill(xx,yy);
	}
	else if(map[xx][yy])
		Add(T,map[xx][yy]),Add(map[xx][yy],T);
		
	xx=x+1,yy=y;
	if( !map2[x+1][y] )
	{
		if( x!=m && !map[xx][yy] )
			Floodfill(xx,yy);
	}
	else if(map[xx][yy])
		Add(T,map[xx][yy]),Add(map[xx][yy],T);

	
}
void BFS()
{
	static int q[65540];
	static unsigned short r,h;
	int i;
	f[q[++r]=map[xa][ya]]=1;
	while(r!=h)
	{
		int x=q[++h];
		for(i=head[x];i;i=table[i].next)
			if(!f[table[i].to])
				f[q[++r]=table[i].to]=f[x]+1;
	}
}
int main()
{
	int i,j;
	cin>>cnt;
	for(i=1;i<=cnt;i++)
		cin>>a[i];
	cin>>xa>>ya>>xb>>yb;

	for(i=1;i<=cnt;i++)
	{
		b[i+i-1]=make_pair(a[i].x,&rectangles[i].x1);
		b[i<<1]=make_pair(a[i].x+a[i].c,&rectangles[i].x2);
	}
	b[cnt<<1|1]=make_pair(xa,&xa);
	b[cnt+1<<1]=make_pair(xb,&xb);
	sort(b+1,b+(cnt+1<<1)+1);
	for(i=1;i<=(cnt+1<<1);i++)
	{
		if(i==1||b[i].first!=b[i-1].first)
			++m;
		*b[i].second=m;
	}
	m+=2;

	for(i=1;i<=cnt;i++)
	{
		b[i+i-1]=make_pair(a[i].y,&rectangles[i].y1);
		b[i<<1]=make_pair(a[i].y+a[i].c,&rectangles[i].y2);
	}
	b[cnt<<1|1]=make_pair(ya,&ya);
	b[cnt+1<<1]=make_pair(yb,&yb);
	sort(b+1,b+(cnt+1<<1)+1);
	for(i=1;i<=(cnt+1<<1);i++)
	{
		if(i==1||b[i].first!=b[i-1].first)
			++n;
		*b[i].second=n;
	}
	n+=2;

	for(i=1;i<=cnt;i++)
	{
		for(j=rectangles[i].x1;j<rectangles[i].x2;j++)
			map1[j][rectangles[i].y1]=map1[j][rectangles[i].y2]=true;
		for(j=rectangles[i].y1;j<rectangles[i].y2;j++)
			map2[rectangles[i].x1][j]=map2[rectangles[i].x2][j]=true;
	}

	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
			if(!map[i][j])
				++T,Floodfill(i,j);

	BFS();
	cout<<f[map[xb][yb]]-1<<endl;
	return 0;
}


资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 行列式是线性代数的核心概念,在求解线性方程组、分析矩阵特性以及几何计算中都极为关键。本教程将讲解如何用C++实现行列式的计算,重点在于如何输出分数形式的结果。 行列式定义如下:对于n阶方阵A=(a_ij),其行列式由主对角线元素的乘积,按行或列的奇偶性赋予正负号后求和得到,记作det(A)。例如,2×2矩阵的行列式为det(A)=a11×a22-a12×a21,而更高阶矩阵的行列式可通过Laplace展开或Sarrus规则递归计算。 在C++中实现行列式计算时,首先需定义矩阵类或结构体,用二维数组存储矩阵元素,并实现初始化、加法、乘法、转置等操作。为支持分数形式输出,需引入分数类,包含分子和分母两个整数,并提供与整数、浮点数的转换以及加、减、乘、除等运算。C++中可借助std::pair表示分数,或自定义结构体并重载运算符。 计算行列式的函数实现上,3×3及以下矩阵可直接按定义计算,更大矩阵可采用Laplace展开或高斯 - 约旦消元法。Laplace展开是沿某行或列展开,将矩阵分解为多个小矩阵的行列式乘积,再递归计算。在处理分数输出时,需注意避免无限循环和除零错误,如在分数运算前先约简,确保分子分母互质,且所有计算基于整数进行,最后再转为浮点数,以避免浮点数误差。 为提升代码可读性和可维护性,建议采用面向对象编程,将矩阵类和分数类封装,每个类有明确功能和接口,便于后续扩展如矩阵求逆、计算特征值等功能。 总结C++实现行列式计算的关键步骤:一是定义矩阵类和分数类;二是实现矩阵基本操作;三是设计行列式计算函数;四是用分数类处理精确计算;五是编写测试用例验证程序正确性。通过这些步骤,可构建一个高效准确的行列式计算程序,支持分数形式计算,为C++编程和线性代数应用奠定基础。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值