`
bobten2008
  • 浏览: 11189 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

POJ 2903 Joy of Mobile Routing

阅读更多

 

/*

从没做过这么复杂的计算几何题,做得我好几次想quit,最后还是坚持写了下来,前前后后花了一天多时间

其实思想还是比较简单的,就是求出所有可以被信号覆盖的点,然后对这些点按照给定的源点和终点进行BFS.

所以难点就在于怎么判断哪些点可以被信号覆盖,主要有以下两点考虑

 

 (1)天线可以覆盖和它在同一行,同一列的点

 (2)对于(1)中未被覆盖的点需要进行额外判断,判断从这点抬头是否可以看到任意一根天线,如果可以即被覆盖

 

第二步的代码书写是最为复杂,因为需要判断当前点与天线的连线与哪些block相交,且是否有相交的block阻挡了

这条线,具体判断方法是:枚举这两点之间的所有block,先判断当前block与连线在平面上是否相交,如果相交,

求出连线与block四条边交点在连线上的高度,如果这个高度小于当前block高度,则block会阻挡信号,即这个天线

不能覆盖当前点

*/

 

 

#include <iostream>
#include <cmath>
#define maxv(a, b) ((a) >= (b) ? (a) : (b))
#define minv(a, b) ((a) <= (b) ? (a) : (b))
#define MAX_N 55
#define MAX_A 105
#define MAX_Q (MAX_N * MAX_N)
using namespace std;

//记录所有的intersection
struct node
{
	int type;	//1: 当前点可以被信号覆盖, 0:当前点不可以被信号覆盖
	int h;      //当前点右下方block的高度
	bool v;     //用于bfs是标识当前点是否被访问过
}nodes[MAX_N][MAX_N];

//记录位置的结构
struct pos
{
	int r, c, h;   //当前位置的行列号,如果这个位置用来表示block或者天线,则还有一个高度信息
};

int R, C, caseN;   //输入图的行列数以及用例个数
int atnum;         //天线个数
pos ats[MAX_A];    //记录天线的信息

pos sp, ep;        //起点和终点

//bfs时队列结构
struct elem
{
	int r, c;
	int step;
};
//bfs队列
elem bfsq[MAX_Q + 1];
int head, tail;

//可以走的四个方向
int dir[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};

//判断当前格子是否为合法格子(没有越界)
bool legalStep(int r, int c)
{
	return r >= 0 && r <= R && c >= 0 && c <= C;
}

//bfs算法,从起点走信号点寻找终点
int bfs()
{
	bool found = false;
	head = tail = 1;
	nodes[sp.r][sp.c].v = true;
	bfsq[tail].r = sp.r; bfsq[tail].c = sp.c; bfsq[tail].step = 0;
	tail = tail % MAX_Q + 1;

	while(head != tail)
	{
		int curR = bfsq[head].r, curC = bfsq[head].c, curStep = bfsq[head].step;
		head = head % MAX_Q + 1;
		//找到终点
		if(curR == ep.r && curC == ep.c) 
		{
			found = true;
			return curStep * 10;
		}
		int newR, newC, newStep;
		//走四个方向
		for(int d = 0; d < 4; d++)
		{
			newR = curR + dir[d][0]; newC = curC + dir[d][1]; newStep = curStep + 1;
			//判断当前方向是否可走
			if(legalStep(newR, newC) && !nodes[newR][newC].v && (nodes[newR][newC].type == 1 || (newR == ep.r && newC == ep.c)))
			{
				nodes[newR][newC].v = true;
				bfsq[tail].r = newR;
				bfsq[tail].c = newC;
				bfsq[tail].step = newStep;
				tail = tail % MAX_Q + 1;
			}
		}
	}
	//无法到达
	if(!found) return -1;
}

//差积
int cross(const pos &p1, const pos &p2, const pos &p3)
{
	return (p3.c * 10 - p1.c * 10) * (p2.r * 10 - p1.r * 10) - (p2.c * 10 - p1.c * 10) * (p3.r * 10 - p1.r * 10);
}

//判断直线[lp11, lp12]与[lp21, lp22],是否相交
bool intersect(const pos &lp11, const pos &lp12, const pos &lp21, const pos &lp22)
{
	int v1 = cross(lp11, lp12, lp21);
	int v2 = cross(lp11, lp12, lp22);
	int v3 = cross(lp21, lp22, lp11);
	int v4 = cross(lp21, lp22, lp12);

	return v1 * v2 < 0 && v3 * v4 < 0;
}

//判断天线a是否可以覆盖点p
bool canReach(const pos &a, const pos &p)
{
	int r, c;
	pos temp1, temp2, temp3, temp4;

	//直线[a, p]的表示

	//直线[a, p]的效率
	double av = (double)(a.r * 10 - p.r * 10) / (double)(a.c * 10 - p.c * 10);
	//直线[a, p]在y轴上的截距离
	double dv = a.r * 10 - av * a.c * 10;

	//点a, p之间的距离
	double dist1 = sqrt(double((a.r * 10 - p.r * 10) * (a.r * 10 - p.r * 10) + (a.c * 10 - p.c * 10) * (a.c * 10 - p.c * 10)));
	double dist2;
	double h = a.h;

	//遍历点a, p之间的block
	for(r = minv(a.r, p.r); r < maxv(a.r, p.r); r++)
	{
		for(c = minv(a.c, p.c); c < maxv(a.c, p.c); c++)
		{
			//取当前block的四个点
			temp1.r = r; temp1.c = c;
			temp2.r = r + 1; temp2.c = c + 1;
			temp3.r = r + 1; temp3.c = c;
			temp4.r = r; temp4.c = c + 1;

			//判断直线[a, p]是否与block[temp1, temp2, temp3, temp4]相交,用到了差积
			if((intersect(a, p, temp1, temp2) || intersect(a, p, temp3, temp4)))
			{
				//分别计算直线[a, p]与当前block四条边所在直线交点的横纵坐标,并判断这个点是否在这个block的边上,如果是则利用等比关系计算当前点在直线[a, p]上的高度,
				//如果这个高度小于当前block的高度,则被阻挡
				double x, y;
				//block的上边
				y = r * 10; x = (y * 10 - dv) / av;
				if(x >= c * 10 && x <= (c + 1) * 10)
				{
					dist2 = sqrt(double((y - p.r * 10) * (y - p.r * 10) + (x - p.c * 10) * (x - p.c * 10)));
					double newh = h * dist2 / dist1;
					if(newh < nodes[r][c].h) return false;
				}
				//block的下边
				y = (r + 1) * 10; x = (y - dv) / av;
				if(x >= c * 10 && x <= (c + 1) * 10)
				{
					dist2 = sqrt(double((y - p.r * 10) * (y - p.r * 10) + (x - p.c * 10) * (x - p.c * 10)));
					double newh = h * dist2 / dist1;
					if(newh < nodes[r][c].h) return false;
				}
				//block的左边
				x = c * 10; y = av * x + dv;
				if(y >= r * 10 && y <= (r + 1) * 10)
				{
					dist2 = sqrt(double((y - p.r * 10) * (y - p.r * 10) + (x - p.c * 10) * (x - p.c * 10)));
					double newh = h * dist2 / dist1;
					if(newh < nodes[r][c].h) return false;
				}
				//block的右边
				x = (c + 1) * 10; y = av * x + dv;
				if(y >= r * 10 && y <= (r + 1) * 10)
				{
					dist2 = sqrt(double((y - p.r * 10) * (y - p.r * 10) + (x - p.c * 10) * (x - p.c * 10)));
					double newh = h * dist2 / dist1;
					if(newh < nodes[r][c].h) return false;
				}
			}
		}
	}
	//可以覆盖
	return true;
}

//预处理,计算所有点是否可以被覆盖
void preProcess()
{
	int i, j, k;
	pos temp;
	//所有天线所在的横纵轴上的点都可以被覆盖
	for(k = 0; k < atnum; k++)
	{
		for(i = 0; i <= C; i++) nodes[ats[k].r][i].type = 1;
		for(j = 0; j <= R; j++) nodes[j][ats[k].c].type = 1;
	}

	//对于上面不和天线在一条横纵线上的点,判断从当前点是否可以看到某个天线的最高点而不被block阻挡
	for(i = 0; i <= R; i++)
	{
		for(j = 0; j <= C; j++)
		{
			if(nodes[i][j].type == 1) continue;
			temp.r = i; temp.c = j;
			for(k = 0; k < atnum; k++)
			{
				if(canReach(ats[k], temp))
				{
					nodes[i][j].type = 1;
					break;
				}
			}
		}
	}


}

int main()
{
	//ofstream output("output.txt");
	int i, j;
	scanf("%d", &caseN);
	while(caseN--)
	{
		scanf("%d%d", &R, &C);
		memset(nodes, 0, sizeof(nodes));
		for(i = 0; i < R; i++)
			for(j = 0; j < C; j++)
				scanf("%d", &nodes[i][j].h);
		scanf("%d%d%d%d", &sp.r, &sp.c, &ep.r, &ep.c);
		scanf("%d", &atnum);
		for(i = 0; i < atnum; i++) scanf("%d%d%d", &ats[i].r, &ats[i].c, &ats[i].h);
		
		preProcess();
		
		cout<<bfs()<<endl;
	}

	
	return 0;
}
分享到:
评论

相关推荐

    poj 2903 Joy of Mobile Routing.md

    poj 2903 Joy of Mobile Routing.md

    poj 2771 Guardian of Decency.md

    poj 2771 Guardian of Decency.md

    poj 3174 Alignment of the Planets.md

    poj 3174 Alignment of the Planets.md

    POJ 3083 Children of the Candy Corn解题报告

    ### POJ 3083 Children of the Candy Corn 解题报告 #### Description 题目描述了一个典型的迷宫问题:在一个玉米地迷宫中,游客需要找到从入口到出口的路径。题目给出了一个常见的策略:选择左墙或右墙并沿着它...

    POJ2151-Check the difficulty of problems

    标题“POJ2151-Check the difficulty of problems”是指一个编程竞赛题目,来源于北京大学的在线判题系统POJ(PKU Online Judge)。这个题目要求参赛者编写程序来评估问题的难度。描述中的“解题报告+AC代码”表明...

    POJ2109-Power of Cryptography

    《POJ2109-Power of Cryptography:解题报告与AC代码解析》 在计算机科学领域,算法和编程竞赛是检验和提升编程技能的重要途径。POJ(Problem Set of Peking University)是由北京大学主办的一个在线编程竞赛平台,...

    POJ2942-Knights of the Round Table【Tarjan算法】

    POJ2942-Knights of the Round Table 【Tarjan算法】 解题报告+AC代码 http://hi.csdn.net/!s/F3L8HO ================================== 我的POJ所有解题报告:...

    POJ.rar_poj java_poj1048

    【描述】"POJ1048,加强版的约瑟夫问题 难度中等" 提示我们,这个问题是编程竞赛POJ(Problemset of JiaoShi University)中的一个挑战,难度适中。约瑟夫问题是经典的计算机科学问题,它源自一个古代犹太人的传说。...

    POJ3253-POJ3253-Fence Repair【STL优先队列】

    标题“POJ3253-POJ3253-Fence Repair【STL优先队列】”指的是一个在线编程竞赛题目,源自北京大学的在线判题系统POJ(Problem Online Judge)。该题目要求参赛者使用C++编程语言解决特定的问题,并且在解决方案中...

    POJ算法题目分类

    * 图的深度优先遍历和广度优先遍历:图的深度优先遍历和广度优先遍历是指遍历图的两种方式,如 poj1860、poj3259、poj1062、poj2253、poj1125、poj2240。 * 最短路径算法:最短路径算法是指计算图中两点之间的最短...

    POJ2739-Sum of Consecutive Prime Numbers

    【描述】该题目来源于北京大学的在线编程平台POJ(Problem Online Judge),编号为2739,名为"Sum of Consecutive Prime Numbers"。这是一道关于算法与数论的编程题目,要求参赛者编写程序来计算连续的素数之和。...

    POJ1010-STAMPS

    【标题】"POJ1010-STAMPS"是一个编程题目,来源于北京大学的在线判题系统POJ(Problem Set of Peking University),这是一处训练程序员算法技能和编程能力的平台。该题目旨在考察参赛者对动态规划或贪心算法的理解...

    POJ1159-Palindrome

    【标题】"POJ1159-Palindrome" 是北京大学在线编程平台POJ上的一道编程题目。这道题目主要考察的是字符串处理和回文判断的知识点。 【描述】"北大POJ1159-Palindrome 解题报告+AC代码" 暗示了解决这道问题的方法和...

    ACM-POJ 算法训练指南

    1. **状态转移方程**:设计复杂的动态规划状态转移方程(poj1191, poj1054, poj3280, poj2029, poj2948, poj1925, poj3034)。 2. **记忆化搜索**:结合动态规划和递归搜索(POJ3254, poj2411, poj1185)。 3. **...

    poj训练计划.doc

    根据给定的文件信息,我们可以总结出一份详细的IT知识训练计划,主要针对编程竞赛和算法学习,特别是聚焦于POJ(Problem Online Judge)平台上的题目训练。这份计划分为两个阶段,初级阶段和中级阶段,共计涉及了165...

    poj题目分类

    * 较为复杂的动态规划:例如 poj1191、poj1054、poj3280、poj2029、poj2948、poj1925、poj3034。 数学 1. 组合数学: * 加法原理和乘法原理。 * 排列组合。 * 递推关系:例如 poj3252、poj1850、poj1019、poj...

    POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类

    - **例题**:poj1860, poj3259, poj1062, poj2253, poj1125, poj2240 - **解释**:最短路径算法包括Dijkstra算法、Bellman-Ford算法、Floyd算法以及堆优化的Dijkstra算法等。 ##### (3) 最小生成树算法 - **例题**...

    POJ2002-Squares

    【标题】"POJ2002-Squares"是一个经典的计算机编程题目,源自北京大学的在线判题系统(POJ,即PKU Online Judge)。这个题目主要涉及到算法设计和实现,尤其是数学和动态规划方面的知识。 【描述】"解题报告+AC代码...

    jihe.rar_2289_POJ 3714_poj3714_poj3714 Ra_visual c

    标题中的"jihe.rar_2289_POJ 3714_poj3714_poj3714 Ra_visual c" 提到了一个压缩文件,可能包含有关编程竞赛或算法解决的资源,特别是与POJ(Problem On Judge)平台上的问题3714相关的。"Ra_visual c"可能指的是...

    poj各种分类

    标题和描述中的“poj各种分类”主要指向的是在POJ(Peking University Online Judge)平台上,根据解题策略和算法类型对题目进行的分类。POJ作为一个知名的在线编程平台,提供了大量的算法练习题,适合从初学者到...

Global site tag (gtag.js) - Google Analytics