HDU 4629 Burning 几何 + 扫描线
总体思路参考了 这里。
细节:1.控制精度,虽然这题没卡精度,不过还是要控制一下。
之前 bool operator<( const Point& A, const Point& B ) 函数没有控制精度,导致了相当大的误差。
2.三点共线的点判掉,虽然不影响结果,但是可以减少点的数目
3.扫入线扫出线的判断:判断第三个点在那两点所形成的的直线的上方还是下方,上方为扫入线, 下方为扫出线
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm> using namespace std; const int MAXN = ; const double eps = 1e-; struct Point
{
double x, y;
int type;
Point( double x = , double y = , int tp = ): x(x), y(y), type(tp) { }
void read_Point()
{
scanf( "%lf%lf", &x, &y );
return;
}
}; struct Line
{
Point a, b; //线段起点,终点
int type; //标记扫入线还是扫出线
Line() {}
Line( Point& x, Point& y, int tp ): a(x), b(y), type(tp) {}
}; int cntX;
vector<double> Lx;
vector<Line> line;
vector<Point> qujian[MAXN];
double ans[]; typedef Point Vector; inline int dcmp( double x ) //控制精度
{
if ( fabs(x) < eps ) return ;
else return x < ? - : ;
} Vector operator+( Vector A, Vector B ) //向量加
{
return Vector( A.x + B.x, A.y + B.y );
} Vector operator-( Vector A, Vector B ) //向量减
{
return Vector( A.x - B.x, A.y - B.y );
} Vector operator*( Vector A, double p ) //向量数乘
{
return Vector( A.x * p, A.y * p );
} Vector operator/( Vector A, double p ) //向量数除
{
return Vector( A.x / p, A.y / p );
} bool operator<( const Point& A, const Point& B ) //两点比较
{
return dcmp( A.x - B.x ) < || ( dcmp( A.x - B.x ) == && dcmp( A.y - B.y ) < );
} bool operator==( const Point& a, const Point& b ) //两点相等
{
return dcmp( a.x - b.x ) == && dcmp( a.y - b.y ) == ;
} double Dot( Vector A, Vector B ) //向量点乘
{
return A.x * B.x + A.y * B.y;
} double Length( Vector A ) //向量模
{
return sqrt( Dot( A, A ) );
} double Angle( Vector A, Vector B ) //向量夹角
{
return acos( Dot(A, B) / Length(A) / Length(B) );
} double Cross( Vector A, Vector B ) //向量叉积
{
return A.x * B.y - A.y * B.x;
} double Area2( Point A, Point B, Point C ) //向量有向面积
{
return Cross( B - A, C - A );
} Vector Rotate( Vector A, double rad ) //向量旋转
{
return Vector( A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad) );
} Vector Normal( Vector A ) //向量单位法向量
{
double L = Length(A);
return Vector( -A.y / L, A.x / L );
} Point GetLineIntersection( Point P, Vector v, Point Q, Vector w ) //两直线交点
{
Vector u = P - Q;
double t = Cross( w, u ) / Cross( v, w );
return P + v * t;
} double DistanceToLine( Point P, Point A, Point B ) //点到直线的距离
{
Vector v1 = B - A, v2 = P - A;
return fabs( Cross( v1, v2 ) ) / Length(v1);
} double DistanceToSegment( Point P, Point A, Point B ) //点到线段的距离
{
if ( A == B ) return Length( P - A );
Vector v1 = B - A, v2 = P - A, v3 = P - B;
if ( dcmp( Dot(v1, v2) ) < ) return Length(v2);
else if ( dcmp( Dot(v1, v3) ) > ) return Length(v3);
else return fabs( Cross( v1, v2 ) ) / Length(v1);
} Point GetLineProjection( Point P, Point A, Point B ) // 点在直线上的投影
{
Vector v = B - A;
return A + v*( Dot(v, P - A) / Dot( v, v ) );
} bool SegmentProperIntersection( Point a1, Point a2, Point b1, Point b2 ) //线段相交,交点不在端点
{
double c1 = Cross( a2 - a1, b1 - a1 ), c2 = Cross( a2 - a1, b2 - a1 ),
c3 = Cross( b2 - b1, a1 - b1 ), c4 = Cross( b2 - b1, a2 - b1 );
return dcmp(c1)*dcmp(c2) < && dcmp(c3) * dcmp(c4) < ;
} /******************以上模板********************/ int N; void init()
{
int len = line.size();
for ( int i = ; i < len; ++i )
for ( int j = i + ; j < len; ++j )
{
//如果线段相交
if ( SegmentProperIntersection( line[i].a, line[i].b, line[j].a, line[j].b ) )
{
//获得交点
Point pp = GetLineIntersection( line[i].a, line[i].b - line[i].a, line[j].a, line[j].b - line[j].a );
Lx.push_back( pp.x );
}
} sort( Lx.begin(), Lx.end() );
cntX = unique( Lx.begin(), Lx.end() ) - Lx.begin();
return;
} void GetAns()
{
for ( int i = ; i <= N; ++i ) ans[i] = 0.0; for ( int i = ; i < cntX - ; ++i )
{
int dep = ; //覆盖度
int sz = qujian[i].size();
double &st = Lx[i], &ed = Lx[i + ];
for ( int j = ; j < sz - ; ++j )
{
dep += qujian[i][j].type;
ans[dep]+=(ed-st)*(qujian[i][j+].x-qujian[i][j].x+qujian[i][j+].y-qujian[i][j].y)/2.0;
}
} for ( int i = ; i <= N; ++i )
printf( "%.10lf\n", ans[i] );
return;
} //void show()
//{
// for ( int i = 0; i < cntX - 1; ++i )
// {
// int sz = qujian[i].size();
// for ( int j = 0; j < sz; ++j )
// {
// printf( "%.6f %.6f %d\n", qujian[i][j].x, qujian[i][j].y, qujian[i][j].type );
// }
// puts("******************\n");
// }
//} void solved()
{
init(); for ( int i = ; i < cntX; ++i ) qujian[i].clear();
int len = line.size(); //遍历每个线段
for ( int i = ; i < len; ++i )
{
//查询线段左端点在Lx的起始位置
int j = lower_bound( Lx.begin(), Lx.begin() + cntX, line[i].a.x ) - Lx.begin();
//遍历线段横跨的区间
for ( ; j < cntX - ; ++j )
{
double st = Lx[j], ed = Lx[j + ];
if ( dcmp( line[i].b.x - ed ) < ) break;
Point p1 =
GetLineIntersection( line[i].a, line[i].b-line[i].a, Point(st,0.0,), Point(,1.0,));
Point p2 =
GetLineIntersection( line[i].a, line[i].b-line[i].a, Point(ed,0.0,), Point(,1.0,));
qujian[j].push_back( Point( p1.y, p2.y, line[i].type ) );
}
} for ( int i = ; i < cntX - ; ++i )
sort( qujian[i].begin(), qujian[i].end() ); GetAns();
return;
} //两点确定直线一般式
void GetABC( Point a, Point b, double& A, double& B, double& C )
{
if( dcmp( a.x - b.x ) == ) B = 0.0;
else B = -1.0;
A = ( b.y - a.y ) / ( b.x - a.x );
C = a.y - A * a.x;
return;
} //判断扫入扫出线
int SaoRuSaoChu( Point p1, Point p2, Point c )
{
double A, B, C;
GetABC( p1, p2, A, B, C );
if ( dcmp( B ) == ) return ; double res = A * c.x + B * c.y + C;
return dcmp( res ) < ? : -; //扫入线 1, 扫出线 -1
} int main()
{
//freopen( "1009.in", "r", stdin );
//freopen( "s.txt", "w", stdout );
int T;
scanf( "%d", &T );
while ( T-- )
{
Lx.clear();
line.clear();
scanf( "%d", &N );
for ( int i = ; i < N; ++i )
{
Point p[];
for ( int j = ; j < ; ++j )
p[j].read_Point(); //判断三点共线
if ( dcmp( Cross( p[] - p[], p[] - p[] ) == ) ) continue; for ( int j = ; j < ; ++j )
{
Lx.push_back( p[j].x );
int k = j + ;
if ( k >= ) k = ;
Line tmpL( p[j], p[k], );
//令a点为线段左端点, b为线段右端点
if ( dcmp( tmpL.b.x - tmpL.a.x ) < ) swap( tmpL.a, tmpL.b ); int m = - j - k; //除了构成线段的两点外的那个点 //判断扫入扫出线
int tp = SaoRuSaoChu( p[j], p[k], p[m] ); //如果这条线垂直于x轴,既不是扫入也不是扫出线
if ( tp == ) continue; //得到扫入扫出线
tmpL.type = tp;
line.push_back( tmpL );
}
} solved();
//printf("lineN = %d cntX=%d\n", (int)line.size(), (int)Lx.size() );
//show();
}
return ;
}
HDU 4629 Burning 几何 + 扫描线的更多相关文章
- hdu 4629 Burning (扫描线)
Problem - 4629 以前写过PSLG模拟的版本,今天写了一下扫描线做这题. 其实这题可以用set存线段来做,类似于判断直线交的做法.不过实现起来有点麻烦,于是我就直接暴力求交点了. 代码如下 ...
- hdu 4052 线段树扫描线、奇特处理
Adding New Machine Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
- hdu 1828 线段树扫描线(周长)
Picture Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- [HDU 4419] Colourful Rectangle (扫描线 矩形面积并)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4419 题目大意:比矩形面积并多了颜色,问染成的每种颜色的面积. 矩形面积并的扫描线维护的是长度,这道题 ...
- hdu 1255(线段树 扫描线) 覆盖的面积
http://acm.hdu.edu.cn/showproblem.php?pid=1255 典型线段树辅助扫描线,顾名思义扫描线就是相当于yy出一条直线从左到右(也可以从上到下)扫描过去,此时先将所 ...
- HDU 5862 Counting Intersections 扫描线+树状数组
题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5862 Counting Intersections Time Limit: 12000/ ...
- HDU 1542 线段树+扫描线+离散化
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- hdu 5091(线段树+扫描线)
上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...
- HDU 5820 Lights(扫描线+zkw线段树)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5820 [题目大意] 在一个大小为50000*50000的矩形中,有n个路灯. 询问是否每一对路灯之 ...
随机推荐
- 安装配置OPENCMS的Replication cluster(从)详细过程
1. 把opencms.war拷贝到tomcat下的webapps目录,启动tomcat服务. 2. 在安装之前,打开解压缩后的war包目录(tomcat启动后会自动把war包解开),删除目录 $ ...
- bzoj 1270 DP
w[i,j]代表高度j,第i颗树的时候的最大值 那么w[i,j]:=max(w[i,j+1],w[k,j+heigh])+sum[i,j]: 但是这样枚举是n^3的,我们发现转移的第二个选择w[k,j ...
- hdu 5120 Intersection
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5120 A ring is a 2-D figure bounded by two circles sh ...
- 堆(heap)和栈(stack)的区别
转: 一.预备知识―程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)― 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中 ...
- Sqli-labs less 25
Less-25 本关主要为or and过滤,如何绕过or和and过滤.一般性提供以下几种思路: 大小写变形 Or,OR,oR 编码,hex,urlencode 添加注释/*or*/ 利用符号 and= ...
- 让IE支持max-width
1:expression在FF下不支持 2:*html内的width不要带单位(px). 3:width:expression(eval(this.offsetWidth>1600?1600:t ...
- POJ 3253 Fence Repair(优先队列,哈夫曼树,模拟)
题目 //做哈夫曼树时,可以用优先队列(误?) //这道题教我们优先队列的一个用法:取前n个数(最大的或者最小的) //哈夫曼树 //64位 //超时->优先队列,,,, //这道题的优先队列用 ...
- 深入浅出ES6(十七):展望未来
作者 Jason Orendorff github主页 https://github.com/jorendorff 出于对文章长度的考虑,我们还保留了一些尚未提及的新特性,在最后的这篇文章中我会集 ...
- 关于SQL查询效率,100w数据,查询只要1秒
1.关于SQL查询效率,100w数据,查询只要1秒,与您分享:机器情况p4: 2.4内存: 1 Gos: windows 2003数据库: ms sql server 2000目的: 查询性能测试,比 ...
- Include Native *.so Library in APK With Android Studio
Originally posted on:http://www.kylethielk.com/blog/include-native-so-library-in-apk-with-android-st ...