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个路灯. 询问是否每一对路灯之 ...
随机推荐
- 网络---中断套接字Socket
package socketpack_2; import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.even ...
- Google Guava学习笔记——基础工具类Splitter的使用
另一项经常对字符串的操作就是根据指定的分隔符对字符串进行分隔.我们基本上会使用String.split方法: String testString = "Monday,Tuesday,,Thu ...
- 用PHP对数据库内容进行操作(改)
查询页面(用户可见) <body> <table width="80%" border="1" cellpadding="0&quo ...
- 02.Hibernate映射基础
前言:Hibernate的核心功能是根据数据库到实体类的映射,自动从数据库绑定数据到实体类.使我们操作实体类(Java对象)就能对数据库进行增.删.查.改,而不用调用JDBC API使数据操作变得简单 ...
- 【Python】Eclipse和pydev搭建Python开发环境
参考资料: http://www.dotnet120.com/page/10545/ 1.准备工作: 下载32位的JDK6 Java的开发包 下载 ...
- [bzoj 3687]简单题 bitset的运用
题意 给定一个正整数集,求所有子集算术和的异或和 题解 每次加入一个元素x,用原集合a xor (a<< x) 然后每一个值统计一下 bitset看起来很优越,是一个能位运算的布尔数组 ...
- 【bzoj1004】[HNOI2008]Cards
1004: [HNOI2008]Cards Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2928 Solved: 1754[Submit][Sta ...
- if in hlsl
seems that in HLSL_4, we can use if https://msdn.microsoft.com/en-us/library/bb313972(v=xnagamestudi ...
- CSS自定义select下拉选择框(不用其他标签模拟)
今天群里有人问到怎么自定义select下拉选择框的样式,于是群里就展开了激烈的讨论,刚开始一直就是考虑怎样使用纯CSS实现,把浏览器默认的样式覆盖掉,但最后均因兼容问题处理不好而失败告终,最后的解决方 ...
- 原 JS监听回车事件
原 JS监听回车事件 发表于2年前(2014-06-04 10:16) 阅读(6101) | 评论(0) 11人收藏此文章, 我要收藏 赞0 1月16日厦门 OSC 源创会火热报名中,奖品多多哦 ...