ZOJ3376 Safest Points [几何(geometry), 宽度优先搜索(bfs)]
2010-08-23 21:47
260 查看
题目大意:在一个w*h的格点区域内,有一些直线,定义一个点是危险点,如果它到某条直线的曼哈顿距离小于1;定义一个点是最安全点,如果它不是危险点,且到所有危险点的最小距离是最大的。如果所有点都是危险点,输出”MISS!”(STG中挂了一次称为1 miss),否则按字典序输出所有最安全点。
分析:首先得把危险点求出来,一个点到一条之间的曼哈顿最近点要么是它水平射线的交点(当直线斜率绝对值大于1时),要么是它垂直射线的交点(当直线斜率绝对值小于1时),证明比较显然。然后对于1000条直线,每条直线都可以用O(1000)的复杂度求出其“附近”的危险点,方法有很多种,但O(1000^2)的方法应该是会TLE的。有了这些危险点后,从这些点出发做一次bfs,求出所有点到危险点的距离,复杂度为O(1000^2)。如果最大的距离等于0,那么”MISS!”,否则就输出所有距离最大的点。
AC代码:
代码
参考博客:http://watashi.ws/blog/1476/zojmonthly1008/
心得:下午比赛时也是用广搜+计算几何做的,当时被没有把所有的距离0点都入队,而是将射线经过的距离0的先入队,广搜是先判断与某点相邻的四个单位边是否与射线集相交,如果相交距离为0,否则为他前驱点距离+1。如果距离有缩小,则入队从新搜索,时间复杂度可想而知……
还是解题报告的方法好啊,先求出所有距离0点,统统入队,再进行宽搜,求出所有点到的射线集的最小曼哈顿距离。然后按字典序遍历距离数组,输出最安全的点,不能用快排的,不然会TLE的。
1.assert函数
2.swap函数
3.queue<pair<int,int> >的使用。
4.解题报告中floor函数的意义,表示不解,望大牛指点……
5.解题报告中求出所有距离0点的处理技巧,保证方向向量dx dy大于0,且dx >dy,否则进行交换。然后mark的时候要根据交换状态进行还原。
分析:首先得把危险点求出来,一个点到一条之间的曼哈顿最近点要么是它水平射线的交点(当直线斜率绝对值大于1时),要么是它垂直射线的交点(当直线斜率绝对值小于1时),证明比较显然。然后对于1000条直线,每条直线都可以用O(1000)的复杂度求出其“附近”的危险点,方法有很多种,但O(1000^2)的方法应该是会TLE的。有了这些危险点后,从这些点出发做一次bfs,求出所有点到危险点的距离,复杂度为O(1000^2)。如果最大的距离等于0,那么”MISS!”,否则就输出所有距离最大的点。
AC代码:
Accepted | 3376 | C++ | 530 | 10112 |
#include<iostream> #include<queue> #include <cassert> using namespace std; int d[1024][1024]; int gcd(int a,int b) { return b==0?a:gcd(b,a%b); } int floor(int a,int b) { if(a<0) return -( (-a+b-1)/b); else return a/b; } int w,h; bool rx,ry,rxy; void mark(int x,int y) { if(rxy) swap(x,y); if(ry) y=-y; if(rx) x=-x; if(0<=x && x<w && 0<=y && y<h) d[x][y]=0; } void gao(int w,int h,int x,int y,int dx,int dy) { if((rx=(dx<0))) w=-w, x=-x, dx=-dx; if((ry=(dy<0))) h=-h, y=-y, dy=-dy; if((rxy=(dx<dy))) swap(w,h), swap(x,y), swap(dx,dy); int g=gcd(dx,dy); dx/=g; dy/=g; for(int i=x; i<w||i<=0; i++) { int j=floor(y*dx+(i-x)*dy,dx); mark(i,j); if((i-x)%dx!=0) mark(i,j+1); } } int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; int main() { int n,x,y,dx,dy,i,j; while(scanf("%d%d%d",&w,&h,&n)!=EOF) { assert(3<=w && w<=1000); assert(3<=h && h<=1000); memset(d,-1,sizeof(d)); for(int k=0;k<n;k++) { scanf("%d%d%d%d",&x,&y,&dx,&dy); assert(0<=x&&x<w); assert(0<=y && y<h); assert(dx!=0 || dy!=0); gao(w,h,x,y,dx,dy); } int maxd=0; queue<pair<int,int> > q; for(i=0;i<w;i++) for(j=0;j<h;j++) if(d[i][j]==0) q.push(make_pair(i,j)); while(!q.empty()) { x=q.front().first; y=q.front().second; q.pop(); for(int k=0;k<4;k++){ dx=x+dir[k][0]; dy=y+dir[k][1]; if(0<=dx&&dx<w && 0<=dy&&dy<h&& d[dx][dy]==-1) { maxd=d[dx][dy]=d[x][y]+1; q.push(make_pair(dx,dy)); } } } if(maxd==0) puts("MISS!"); else{ bool blank=false; for(i=0;i<w;i++) for(j=0;j<h;j++) if(d[i][j]==maxd) { if(blank) putchar(' '); blank=true; printf("(%d, %d)",i,j); } puts(""); } } return 0; }
参考博客:http://watashi.ws/blog/1476/zojmonthly1008/
心得:下午比赛时也是用广搜+计算几何做的,当时被没有把所有的距离0点都入队,而是将射线经过的距离0的先入队,广搜是先判断与某点相邻的四个单位边是否与射线集相交,如果相交距离为0,否则为他前驱点距离+1。如果距离有缩小,则入队从新搜索,时间复杂度可想而知……
还是解题报告的方法好啊,先求出所有距离0点,统统入队,再进行宽搜,求出所有点到的射线集的最小曼哈顿距离。然后按字典序遍历距离数组,输出最安全的点,不能用快排的,不然会TLE的。
1.assert函数
2.swap函数
3.queue<pair<int,int> >的使用。
4.解题报告中floor函数的意义,表示不解,望大牛指点……
5.解题报告中求出所有距离0点的处理技巧,保证方向向量dx dy大于0,且dx >dy,否则进行交换。然后mark的时候要根据交换状态进行还原。
相关文章推荐
- POJ 3626 Mud Puddles 练习 BFS 宽度优先搜索
- 【算法入门】广度/宽度优先搜索(BFS)
- 【算法入门】广度/宽度优先搜索(BFS)
- POJ 3626 Mud Puddles 练习 BFS 宽度优先搜索
- 【算法入门】广度/宽度优先搜索(BFS)
- 广度/宽度优先搜索(BFS)
- 广度/宽度优先搜索(BFS)
- 广度/宽度优先搜索(BFS)
- 广度/宽度优先搜索(BFS)
- BFS宽度优先搜索思想
- poj 3278(bfs宽度优先搜索)
- 多叉树的宽度优先搜索BFS
- BFS宽度优先搜索思想
- 【算法入门】广度/宽度优先搜索(BFS)
- 广度/宽度优先搜索(BFS)
- BFS-迷宫问题-用宽度(广度)优先搜索解决最优路径问题
- BFS宽度优先搜索思想
- uva 816 有点复杂的BFS和宽度优先搜索模板 Abbott's Revenge
- 穿越雷区--bfs宽度优先搜索
- BFS-宽度优先搜索(Breadth First Search)—1