能解决一个判定可视范围的code,SLAM相关

本文介绍了一种光线追踪算法的实现及优化过程,包括使用结构化数据加速计算、减少重复计算等技巧,使得算法效率提升了70%。适用于游戏开发、图形渲染等领域。

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

换队长来写,估计20min解决。

而我写了8个小时QAQ

 

 

#include <bits/stdc++.h>
using std::cin;
using std::endl;
using std::cout;


struct pix
{
	int x, y;
	pix(){}
	pix(int a,int b):x(a),y(b){}
};
std::ostream& operator << (std::ostream &f, pix a)
{
	f<<"("<<a.x<<","<<a.y<<")";
	return f;
}

int operator == (pix A, pix B)
{
	return (A.x == B.x && A.y == B.y);
}

inline int isRightHand(pix A, pix B)
{
	//返回大于0的数字,则满足A是B的右手螺旋方向
	//0表示2向量共线
	//小于0,则B是A的右手螺旋方向 
	return B.y*A.x - A.y*B.x;
}


class solve{
	private:
		int X, Y;//col-> X   row->Y
		std::vector<std::vector<int> > map;
		std::vector<std::vector<int> > vis;
		std::vector<std::vector<int> > cho;//选中状态
	public:
		void init(const std::string &filename)
		{
			std::ifstream ifs;
			ifs.open(filename.c_str());
			ifs >> X >> Y;
			map.clear();
			map.resize(X);
			for (int i = 0; i < X; ++ i)
			{
				map[i].resize(Y);
				for (int j = 0; j < Y; ++ j)
				{
					ifs >> map[i][j];
				}
			}
			for (int i = 0; i < X; ++ i)
			{
				map[i][0] = map[i][Y-1] = 1;
			}
			for (int i = 0; i < Y; ++ i)
			{
				map[0][i] = map[X - 1][i] = 1;
			}
			ifs.close();
			cho = vis = map;
		}

		void fill(int nx, int ny, int dx, int end, int flag ,int dy=0x7ffffff)
		{
			if (dy != 0x7ffffff)
			{
				//此为竖着画
				for (int i = ny; i != end; i += dy)
				{
					/*
					if (vis[nx][i] != 0)	//这一竖排已经填过了
					{
						break;
					}
					*/
					if (map[nx][i] == 1 && flag == 1)
					{
						fill(nx, i, dx, end, -1, dy);
						break;
					}
					vis[nx][i] = flag;
				}
			}
			else
			{


				for (int i = nx; i != end; i += dx)
				{
					if (vis[i][ny] != 0)	//这行已经填好了
					{
						break;
					}
					if (map[i][ny] == 1 && flag == 1)
					{
						fill(i, ny, dx, end, -1);
						break;
					}
					vis[i][ny] = flag;
				}
			}
		}
		int centerx, centery;

		//循环模拟递归
		int flag=0;
		void update(int nx, int ny, int dx, int dy, int endx, int endy)
		{
//#define debug
			if (flag) 
			{
				cout<<"    开始处理("<<nx<<","<<ny<<")"<<endl;
			}
			int y = ny;
			double k = (double)(nx-centerx) / (double)(ny-centery);
			for (; ; y -= dy)
			{
				int x;
				if (dx > 0)
				{
					x = std::ceil(k * ((y - centery)- 0.5 * dy)) + centerx;
				}
				else
				{
					x = std::floor(k * ((y - centery)- 0.5 * dy)) + centerx;
				}

				if (flag)
				{
					printf("在%d行,是第%d个元素开始有光通过  ", y, x);
					printf("上一行是第%d行,第%d个元素,这个元素的取值为%d\n",y-dy, x-dx, vis[x-dx][y-dy]);
				}
				if (vis[x - dx][y - dy] == 1)
				{
					//下一层光是通的
					break;
				}
				if (vis[x - dx][y - dy] == -1)
				{
					//下一层光不通
					break;
				}
				//下一层未知,则继续
			}
			for (; y != ny + dy ;y += dy)
			{
				int x;
				if (dx > 0)
				{
					x = std::ceil(k * ((y - centery)- 0.5 * dy)) + centerx;
				}
				else
				{
					x = std::floor(k * ((y - centery)- 0.5 * dy)) + centerx;
				}
				/*
				if (flag)
				{
					cout << x<<" "<<y<<" !"<<endl;
					cout<< vis[x-dx][y-dy]<<endl;
				}
				*/
				if (vis[x - dx][y - dy] == -1 || vis[x][y - dy] == -1)
				{
					//如果上一个节点光路不通,那么这一行肯定光路也都不通
					fill(x, y, dx, endx, -1);
					continue;
				}
				//if (flag)	cout<<x<<" "<<y<<"@@@"<<endl;
				//剩下的情况,就是光路通的情况
				fill(x, y, dx, endx, 1);
			}
		}


		void pg()
		{
			for (int i = 0; i < X; ++ i)
			{
				for (int j = 0; j < Y; ++ j)
				{
					printf("%d\t", vis[i][j]);
					//cout << vis[i][j]<<" ";
				}
				cout << endl;

			}
		}

		void output()
		{
			for (int i = 0; i < X; ++ i)
			{
				for (int j = 0; j < Y; ++ j)
				{
					printf("%d\t", vis[i][j]==-1?0:1);
					//cout << vis[i][j]<<" ";
				}
				cout << endl;
			}
		}

		void core()
		{
			//vis[i][j] 为0,则该点状态未知,1为可行。 -1为不可达
			centerx = X / 2;
			centery = Y / 2;
			//cout<<X<<" "<<Y<<endl;
			for (int i = 0; i < X; ++ i)
			{
				for (int j = 0; j < Y; ++ j)
				{
					vis[i][j] =0;
				}
			}

			vis[centerx][centery] = 1;
			fill(centerx +1, centery, 1, X, 1);
			fill(centerx -1, centery, -1, -1, 1);
			//第一象限

			for (int y = centery +1; y != Y; ++ y)
			{
				update(X -1, y, 1, 1, X ,Y);
			}

			for (int x = X - 2; x > centerx; -- x)
			{
				update(x, Y - 1, 1, 1, X ,Y);
			}

			//第二象限
			for (int y = centery + 1; y != Y; ++ y)
			{
				update(0, y, -1, 1, -1, Y);
			}

			//flag = 1;
			for (int x = 1; x != centerx; ++ x)
			{
				update(x, Y - 1, -1, 1, -1, Y);
				//pg();
			}
			//flag = 0;
			//exit(0);

			//第三象限
			for (int y = centery -1; y >= 0; -- y)
			{
				update(0, y, -1, -1, -1, -1);
			}
			for (int x = 0; x < centerx; ++ x)
			{
				update(x, 0, -1, -1, -1, -1);
			}



			//第四象限
			for (int y = centery -1; y >=0; -- y)
			{
				update(X-1, y, 1, -1, X, -1);
			}
			for (int x = X -1; x > centerx; -- x)
			{
				update(x, 0, 1, -1, X, -1);
			}

			
			fill(centerx, centery - 1, 0, -1, 1, -1);
			fill(centerx, centery + 1, 0, Y ,1, 1);
 
			for (int x = 0; x < X;++x)
				for (int y = 0; y < Y; ++ y)
					if (vis[x][y]==0)
					{
						cout<<x<<" "<<y<<endl;
						exit(0);
					}
		}


};

int main()
{
	solve x;
	x.init("data.txt");
	x.core();
	x.output();
	return 0;
}

/*
   10 10
   1 1 1 1 1 1 1 1 1 1
   1 0 0 0 0 1 1 0 1 1
   1 1 0 1 1 1 1 0 0 1
   1 0 0 0 0 0 0 0 0 1
   1 1 0 0 0 0 0 0 0 1
   1 1 1 0 0 0 0 0 0 1
   1 1 0 0 0 0 0 0 0 1
   1 1 0 0 0 0 0 1 0 1
   1 1 1 1 0 0 0 0 0 1
   1 1 1 1 1 1 1 1 1 1
   */

 

 

然后速度提升70%后的程序

 

 

 

//2017-10-15 21:31:37
//by me!
//更新说明:
//修改了类的定义方式,在定义solve的同时指定地图大小。
//取消了vector设定,预处理了double计算,优化了常数
//最终完成样例png大致计算所用时间大约5-10 ms
//可以考虑的优化方案:在预处理除法的同时考虑象限变换,利用对称性减少除法次数。

#include <bits/stdc++.h>
using std::cin;
using std::endl;
using std::cout;

/*
 * 直接调用init data
 * data第一行n m表示下面数据有n行,m列
 * 接着有n行,每行m个数字。每个数字非0即1!
 * 1表示有障碍。
 * 调用完init后,调用run函数。接着output则为输出整个图片(n行m列,每个数字非0即1)
 * */

template<int size_X, int size_Y> //地图的高!和宽!!
class solve{
	private:
		int X, Y;
		bool map[size_X][size_Y];
		int vis[size_X][size_Y];
		double kk[size_X][size_Y];
		int centerx, centery;

	public:
		int debug;
		double st;

		void thickenWall(int nx, int ny, int dx, int dy, int endx, int endy){
			memset(vis, 0, sizeof(vis));
			for (int x = nx; x != endx - dx; x += dx)
				for (int y = ny; y != endy; y += dy){
					if (map[x][y] == 0)	continue;
					if (map[x+dx][y-dy])	vis[x][y] = 1;

				}
			for (int x = nx; x != endx; x += dx)
				for (int y = ny ; y != endy; y += dy)
					if (vis[x][y])	map[x + dx][y] = 1;
		}

		void init(const std::string &filename){
			std::ifstream ifs;
			ifs.open(filename.c_str());
			debug=0;
			ifs >> X >> Y;
			centerx = X / 2;
			centery = Y / 2;
			for (int i = 0; i < X; ++ i){
				for (int j = 0; j < Y; ++ j){
					ifs >> map[i][j];
					kk[i][j] = (double)(i - centerx) / (double)(j - centery);
				}
			}
			st=clock();
			thickenWall(centerx + 1, centery + 1,  1,  1,  X,  Y);
			thickenWall(centerx - 1, centery + 1, -1,  1, -1,  Y);
			thickenWall(centerx - 1, centery - 1, -1, -1, -1, -1);
			thickenWall(centerx + 1, centery - 1,  1, -1,  X, -1);
			for (int i = 0; i < X; ++ i)
				map[i][0] = map[i][Y-1] = true;
			for (int i = 0; i < Y; ++ i)
				map[0][i] = map[X - 1][i] = true;
			ifs.close();
		}

		void fill(const int &nx, const int &ny, const int &dx, int end, int flag ,int dy=0x7ffffff){
			if (dy != 0x7ffffff){
				for (int i = ny; i != end; i += dy){
					if (map[nx][i] && flag == 1)
					{
						fill(nx, i, dx, end, -1, dy);
						break;
					}
					vis[nx][i] = flag;
				}
			}
			else
			{
				if (nx == centerx)	fill(nx + dx, ny, dx, end, flag);
				for (int i = nx; i != end; i += dx){
					if (vis[i][ny] != 0)	break;
					if (map[i][ny] && flag == 1){
						fill(i, ny, dx, end, -1);
						break;
					}
					vis[i][ny] = flag;
				}
			}
		}

		int getxxx(int &x, int &xxx, const double &k, const int &y, const int &dy, const int &dx){
			if (dx > 0){
				x   = std::ceil(k * ((y - centery ) - 0.5 * dy)) + centerx;
				int tmp = std::floor(k * ((y - centery) + 0.5 * dy)) + centerx;
				if (x > tmp) 	x = std::move(tmp);
				xxx = std::floor(k * ((y - centery -dy) + 0.5 * dy)) + centerx; 
			}
			else{
				x   = std::floor(k * ((y - centery ) - 0.5 * dy)) + centerx;
				int tmp = std::ceil(k * ((y - centery ) + 0.5 * dy)) + centerx;
				if (x < tmp)	x= std::move(tmp);
				xxx = std::ceil(k * ((y - centery -dy) + 0.5 * dy)) + centerx;
			}
			return vis[xxx][y-dy];
		}

		void update(int nx, int ny, int dx, int dy, int endx, int endy){
			int y = ny, x, xxx;
			double k = kk[nx][ny];//(double)(nx-centerx) / (double)(ny-centery);
			for (; !getxxx(x, xxx, k, y, dy, dx); y -= dy);
			for (; y != ny + dy ;y += dy){
				getxxx(x, xxx, k, y, dy, dx);
				if (vis[xxx][y - dy] == -1 )		fill(x, y, dx, endx, -1);
				else	fill(x, y, dx, endx, 1);
			}
		}

		void output(){
			for (int i = 0; i < X; ++ i){
				for (int j = 0; j < Y; ++ j)
					printf("%d\t", vis[i][j]==-1?0:1);
				printf("\n");
			}
		}

		void core(){
			memset(vis, 0, sizeof(vis));
			vis[centerx][centery] = 1;
			fill(centerx +1, centery, 1, X, 1);
			fill(centerx -1, centery, -1, -1, 1);
			for (int y = centery +1; y != Y; ++ y)		update(X -1, y, 1, 1, X ,Y);
			for (int x = X - 2; x > centerx; -- x)		update(x, Y - 1, 1, 1, X ,Y);
			fill(centerx, centery + 1, 0, Y ,0, 1);
			for (int y = centery + 1; y != Y; ++ y)		update(0, y, -1, 1, -1, Y);
			for (int x = 1; x != centerx; ++ x)		update(x, Y - 1, -1, 1, -1, Y);
			for (int y = centery -1; y >= 0; -- y)		update(0, y, -1, -1, -1, -1);
			for (int x = 0; x < centerx; ++ x)		update(x, 0, -1, -1, -1, -1);
			fill(centerx, centery - 1, 0, -1, 0, -1);
			for (int y = centery -1; y >=0; -- y)		update(X-1, y, 1, -1, X, -1);
			for (int x = X -1; x > centerx; -- x)		update(x, 0, 1, -1, X, -1);
			fill(centerx, centery - 1, 0, -1, 1, -1);
			fill(centerx, centery + 1, 0, Y ,1, 1);

			for (int x = 0; x < X;++x)
				for (int y = 0; y < Y; ++ y)		assert(vis[x][y]);
		}
};
solve<500,400> x;
int main()
{
	x.init("data.txt");
	x.core();
	//cout<<"程序计算时间为(不算输出和读入时间)";
	//cout<< (clock()-x.st)/ CLOCKS_PER_SEC << " 秒"<<endl;
	//return 0;
	if (!x.debug)	x.output();
	return 0;
}


 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值