hdu3511-Prison Break

纪念一下人生中第一道扫描线算法的题。。。。。其实不是严格上的第一道。。。第一次遇到的那个至今没过。。。。。

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3511

这题应该算是扫描线的基础题。

对于每个圆,进入和出去的时候分别做扫描线,分别是x = c[i].x - c[i].r, x‘ = c[i].x + c[i].r;

这样对于每条扫描线,对于x‘,我们在集合中删去这个圆,这很好理解。

对于x,我们将这个圆加入集合,这样我们只要找向上第一个交的点和向下第一个交的点即可。

不过问题来了,这个交点坐标随着扫描线的移动是在变化的,但我们注意到,这些点的相对位置并不变(即上面的还在上面,下面的还在下面)

这样我们可以拉个set来维护扫描线上交点纵坐标,这个没必要存这个纵坐标的具体值,因为相对位置不变,树的结构也不变。

只需要重载一下小于号在insert时候使用即可。

如果扫描线向上或向下没有点,那么这个圆的depth = 1;

如果上下两个点属于同一个圆id,那么这个圆的depth = depth[id]+1;

如果上下两个圆属于不同的圆id1,id2,那么这个圆的depth = max(depth[id1], depth[id2]);

AC代码:

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4 const int maxn = 50000 + 10;
  5
  6 typedef struct Circle{
  7   int id, x, y, r;
  8
  9   Circle( int id = 0, int x = 0, int y = 0, int r = 0 ){
 10     this->id = id;
 11     this->x = x;
 12     this->y = y;
 13     this->r = r;
 14   }
 15 }Circle;
 16
 17 Circle c[maxn];
 18
 19 typedef struct Point{
 20   int id, ty;
 21
 22   Point( int id = 0, int ty = 0 ){
 23     this->id = id;
 24     this->ty = ty;
 25   }
 26 }Point;
 27
 28 set<Point> s;
 29
 30 typedef struct Line{
 31   int id, x, ty;
 32
 33   Line( int id = 0, int x = 0, int ty = 0 ){
 34     this->id = id;
 35     this->x = x;
 36     this->ty = ty;
 37   }
 38
 39   bool operator < ( const Line& l )const{
 40     if( x == l.x )
 41       return id < l.id;
 42     return x < l.x;
 43   }
 44 }Line;
 45
 46 Line l[maxn<<1];
 47
 48 int depth[maxn];
 49
 50 int n, ans, xlog;
 51
 52 double intersector( const Point& p ){
 53   int id = p.id;
 54   double r = 1.0*c[id].r;
 55
 56   double x = 1.0*(xlog - c[id].x);
 57   double y = sqrt((r*r - x*x));
 58
 59   if(p.ty == 1)
 60     return 1.0*c[id].y + y;
 61   else
 62     return 1.0*c[id].y - y;
 63 }
 64
 65 bool operator < ( const Point& p1, const Point& p2 ){
 66   if(p1.id == p2.id)
 67     return p1.ty < p2.ty;
 68   return intersector(p1) < intersector(p2);
 69 }
 70
 71 void solve( int nn ){
 72   memset(depth, 0, sizeof(depth));
 73   s.clear();
 74   ans = 0;
 75
 76   for( int i = 0; i < nn; ++i ){
 77     int id = l[i].id, ty = l[i].ty;
 78     xlog = l[i].x;
 79     //cout << "id: " << id << "   ty: " << ty << endl;
 80
 81     if( ty == 1 ){
 82       s.erase(Point(id, 0));
 83       s.erase(Point(id, 1));
 84     }else{
 85       s.insert(Point(id, 0));
 86       set<Point>::iterator it1 = s.find(Point(id, 0)), it2;
 87       it2 = it1;
 88       it2++;
 89
 90       if( it1 == s.begin() || it2 == s.end() ){
 91         depth[id] = 1;
 92         //cout << "id: " << id << "    depth[id]: " << depth[id] << endl;
 93       }else{
 94         it1--;
 95         if( it1->id == it2->id ){
 96           depth[id] = depth[it1->id]+1;
 97         }else{
 98           depth[id] = max( depth[it1->id], depth[it2->id] );
 99         }
100         //cout << "id: " << id << "    depth[id]: " << depth[id] << endl;
101       }
102       s.insert(Point(id, 1));
103     }
104     ans = max( ans, depth[id]);
105   }
106
107   printf("%d\n", ans);
108 }
109
110 int main(void){
111   while(scanf("%d", &n) != EOF){
112     memset( c, 0, sizeof(c) );
113     memset( l, 0, sizeof(l) );
114
115     for( int i = 0; i < n; ++i ){
116       c[i].id = i;
117       scanf("%d%d%d", &c[i].x, &c[i].y, &c[i].r);
118       l[i*2] = Line(i, c[i].x-c[i].r, 0);
119       l[i*2+1] = Line(i, c[i].x+c[i].r, 1);
120     }
121     int nn = n * 2;
122     sort( l, l + nn );
123
124     solve(nn);
125   }
126
127   return 0;
128 }
129
130 /*
131 5
132 0 0 100
133 0 0 1
134 0 5 3
135 3 0 2
136 0 0 200
137 6
138 0 0 100
139 0 0 1
140 0 5 3
141 0 5 2
142 3 0 2
143 0 0 200
144 */

时间: 2024-08-06 11:05:43

hdu3511-Prison Break的相关文章

HDU 3681 Prison Break(bfs+二分+状压DP)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3778    Accepted Submission(s): 992 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

hdu 3681 Prison Break(状态压缩+bfs)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

hdu 3681 Prison Break (状态压缩+bfs+最短路)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3214    Accepted Submission(s): 829 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

HDU3681 Prison Break(状压dp)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

hdu 3511 Prison Break

http://acm.hdu.edu.cn/showproblem.php?pid=3511 题意: 给出n个相离或包含的圆,问最里层的圆是第几层 竖着的扫描线与圆在最左侧相切时 1.线在圆的上方或下方无交点,则该圆在第1层 2.线在圆的上下方都有交点,且上下方的交点属于同一个圆C,则该圆在圆C的里面一层 3.线在圆的上下方都有交点,上方交于圆E,下方交于圆F,EF其中一个在另一个里面,则该圆与在里面的那个圆处在同一层 4.线在圆的上下方都有交点,上方交于圆E,下方交于圆F,EF在同一层,则该圆

1254 - Prison Break

  PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Michael Scofield has just broken out of the prison. Now he wants to go to a certain city for his next unfinished job. As you are the only programmer on his gang, he asked yo

HDU3681(Prison Break)

题目链接:传送门 题目大意:给你一副n*m大小的图,'D'表示墙,'F'表示起点,'S'表示空地,'G'表示能源站,'Y'表示开关,一开始机器人处在'F'并有一个初始能量,每走一步会消耗一格能量 机器人需要在能量耗尽前经过所有'Y'至少一次,其中经过'G'可补满能量回初始值但每个'G'只能补一次,问至少需要几个能量才能达到要求. 题目思路:这个题感觉真的是很考验功底,集bfs,状态压缩DP,二分于一身,且实现细节不能马虎,实在是一道好题. 为什么说是状态压缩DP,You can assume t

HDU 3681 Prison Break floyd+状压+二分

题目链接:点击打开链接 题意: 给定n*m的矩阵: F:起点(有且仅有一个) D:坏点(不能走到这个点) G:能量池(走到这个点可以选择使用这个点的能量池,把电池充满,也可以暂时不用,只能使用一次) Y:目标点 问: 遍历所有Y点需要最小的电池容量是多少. 开始电池满电,每走一步消耗一格电. Y+G的个数<=15. n,m<=15 思路:状压YG,前面几位表示Y,后面几位表示G. 先跑个floyd,然后二分电池容量,状压dp判可行 #include <cstdio> #includ

【状压+二分+BFS】HDU 3681 Prison Break

通道:http://acm.hdu.edu.cn/showproblem.php?pid=3681 题意:机器人从F出发,走到G可以充电,D不能走进,走到Y关掉开关,要求把所有开关关掉,且电量最少,并求出初始最小电量. 思路:二分初始的电量,预处理任意G,Y,F之间的最短距离,然后状压dp[s][u]:状态为s的u为起点遍历整个图的最小布数. 代码:https://github.com/Mithril0rd/Rojo/blob/master/hdu3681.cpp TAG:代码来自华仔

HDU 3681 Prison Break

/* 给一个n*m的图,F代表起点,G代表充电池,一个充电池只能用一次,但可以用多个充电池,只能把电池充到最大(原始的电量),可以走过不用,D不能走, 问的是把所有的Y走一遍的原始的电量是多少 dp+状态压缩+二分+bfs dp[i][j]表示的状态是在i状态到达j的最大的电量 */ #include<stdio.h> #include<string.h> #include<queue> #define Max(a,b) a>b?a:b #define Min(a