HDU 3961 Crisis【恶心的几何模拟】
链接: http://acm.hdu.edu.cn/showproblem.php?pid=3961这题竟然有队伍场上过掉了。。大神们的脑子得有多清楚。。。我这题是做了一天才理清思路,过了样例。。这题的样例就已然强的一B了。。
题目大意即做法,题意很裸,直接把做法说出来了,所以就是模拟题咯。
先给你一个圆和圆外一点,然后给你一个多边形(不一定凸凹),将多边形绕圆心公转,同时自转,给你转动周期和时间。
让你求圆外点向圆发出光线,除去被多边形挡住的部分后,被照弧的弧长有多少。
就模拟呗:
用圆外点求到圆的两条公切线的切点,解一个二元二次方程和一个二元一次方程联立。
(x0,y0)圆心坐标 (xp,yp)圆外点坐标
(xp - x0)(x - x0) + (yp - y0)(y - y0) = r^2
(x - x0)^2 + (y - y0)^2 = r^2
得到切点cutl,cutr(根据cmp函数判断一下两者相对关系,为之后极角排序找点比较做准备)
仿射变换公式:(x,y) 转theta角到(x*cos(theta) - y*sin(theta),x*sin(theta)+y*cos(theta))
求多边形重心,记录一下重心到各顶点的向量,将重心公转到指定位置(应用二维仿射变换),再用向量还原多边形,再绕重心自转多边形。
此时对多边形上的进行极角排序,找出两端的点L,R。
判断找到的两点是否在(xp,yp),cutl,cutr 构成的三角形内。我用了个麻烦的方法,是先根据叉积的左右手性判断一部分情况的,后续说明。
再用(xp,yp)和L,R求直线方程,再用直线方程联立圆方程求解交点坐标。
ax+by+c=0
(x-x0)^2 + (y-y0)^2 = r^2
紧跟前步,用交点坐标到(xp,yp)的距离和L、R比较来判断多边形是否在圆后。
唉,这个好麻烦啊写的。。还是天王的方法好,直接用(xp,yp)、cutl、cutr、(x0,y0)构成四边形,判断交点是否在四边形内即可。
最后用点积除以模长再求acos的方法计算圆心角和弧长,再相减即可。
圆心角alpha = acos(vectorL * vectorR / (|vectorL|*|vectorR|))
注意用acos的时候要调整精度,因为除法可能会得出一个大于1的数字,这样acos就bug了。。。精度伤不起啊。
代码随手贴一下,写了一天半的代码,太矬了,弱爆了:
#include
<
iostream
>
#include < cstdio >
#include < cmath >
#include < cstring >
#include < algorithm >
#define maxn 105
using namespace std;
const double pi = acos( - 1.0 );
struct point
{
double x,y;
point(){}
point( double a, double b):x(a),y(b){}
point operator - ( const point & p)
{
return point(x - p.x,y - p.y);
}
point operator + ( const point & p)
{
return point(x + p.x,y + p.y);
}
double operator * ( const point & p)
{
return x * p.x + y * p.y;
}
double operator ^ ( const point & p)
{
return x * p.y - y * p.x;
}
double norm()
{
return sqrt(x * x + y * y);
}
}sun,earth,vec[maxn],p[maxn],cutl,cutr;
double multi(point a,point b,point o)
{
return (a - o) ^ (b - o);
}
double r;
int T1,T2,T;
int n;
const double eps = 1e - 6 ;
int comp( double x)
{
if (fabs(x) < eps)
return 0 ;
else if (x < - eps)
return - 1 ;
else
return 1 ;
}
point rotate(point a,point o, double theta)
{
point vec = a - o;
point to = point(vec.x * cos(theta) - vec.y * sin(theta),vec.x * sin(theta) + vec.y * cos(theta));
return o + to;
}
double tarea(point p0,point p1,point p2)
{
double k = p0.x * p1.y + p1.x * p2.y + p2.x * p0.y - p1.x * p0.y - p2.x * p1.y - p0.x * p2.y;
return k / 2 ;
}
bool cmp(point p,point q)
{
double t1 = atan2(p.y - sun.y,p.x - sun.x),t2 = atan2(q.y - sun.y,q.x - sun.x);
return (comp(t1 - t2) > 0 );
}
struct line
{
double a,b,c;
line(){}
line(point p,point q)
{
if (comp(p.x - q.x) == 0 )
{
a = 1.0 ;
b = 0.0 ;
c = - p.x;
}
else if (comp(p.y - q.y) == 0 )
{
a = 0.0 ;
b = 1.0 ;
c = - p.y;
}
else
{
a = 1.0 ;
b = - (p.x - q.x) / (p.y - q.y);
c = - (p.x + b * p.y);
}
}
};
bool arc(line llll,point & P)
{
double a = llll.a,b = llll.b,c = llll.c;
double A = b * b + 1 ,B = 2.0 * b * c + 2.0 * b * earth.x - 2.0 * earth.y,C = c * c + 2.0 * c * earth.x + earth.x * earth.x + earth.y * earth.y - r * r;
double det = B * B - 4.0 * A * C;
if (comp(det) < 0 )
return false ;
else if (comp(det) == 0 )
{
double x,y;
y = ( - B + sqrt(det)) / ( 2.0 * A);
x = - (b * y + c);
point w(x,y);
P = w;
return true ;
}
else
{
double y1 = ( - B + sqrt(det)) / ( 2.0 * A),y2 = ( - B - sqrt(det)) / ( 2.0 * A);
double x1 = - (b * y1 + c),x2 = - (b * y2 + c);
point w1(x1,y1),w2(x2,y2);
double dis1 = (w1 - sun).norm(),dis2 = (w2 - sun).norm();
if (comp(dis1 - dis2) > 0 )
P = w2;
else
P = w1;
return true ;
}
}
void calc()
{
double a,b,c;
a = (sun.y - earth.y) * (sun.y - earth.y) + (sun.x - earth.x) * (sun.x - earth.x);
b = - 2.0 * earth.y * ((sun.y - earth.y) * (sun.y - earth.y) + (sun.x - earth.x) * (sun.x - earth.x)) - 2.0 * r * r * (sun.y - earth.y);
c = r * r * r * r + 2.0 * r * r * (sun.y - earth.y) * earth.y - r * r * (sun.x - earth.x) * (sun.x - earth.x) + earth.y * earth.y * ((sun.y - earth.y) * (sun.y - earth.y) + (sun.x - earth.x) * (sun.x - earth.x));
double det = b * b - 4.0 * a * c;
double y1 = ( - b + sqrt(det)) / ( 2.0 * a),y2 = ( - b - sqrt(det)) / ( 2.0 * a);
double x1 = (r * r - (sun.y - earth.y) * (y1 - earth.y)) / (sun.x - earth.x) + earth.x;
double x2 = (r * r - (sun.y - earth.y) * (y2 - earth.y)) / (sun.x - earth.x) + earth.x;
cutl = point(x1,y1),cutr = point(x2,y2);
if ( ! cmp(cutl,cutr))
swap(cutl,cutr);
}
double len(point a,point b)
{
point vec1 = point(a - earth),vec2 = point(b - earth);
double value = (vec1 * vec2) / (vec1.norm() * vec2.norm());
if (comp(value - 1.0 ) >= 0 )
value = 1.0 ;
double theta = acos(value);
return r * theta;
}
int main()
{
while (scanf( " %lf %lf %lf %lf %lf " , & sun.x, & sun.y, & earth.x, & earth.y, & r) == 5 )
{
// calc arc
calc();
scanf( " %d %d %d %d " , & n, & T1, & T2, & T);
for ( int i = 0 ;i < n;i ++ )
{
double x,y;
scanf( " %lf %lf " , & x, & y);
p[i] = point(x,y);
}
int t1 = T % T1,t2 = T % T2;
double gong = 2.0 * pi * ( double )t1 / ( double )T1,zi = 2.0 * pi * ( double ) t2 / ( double ) T2;
point zhong,temp( 0 , 0 );
double area = 0 ,sumx = 0 ,sumy = 0 ,sarea = 0 ;
for ( int i = 1 ;i < n - 1 ;i ++ )
{
temp.x = p[ 0 ].x + p[i].x + p[i + 1 ].x;
temp.y = p[ 0 ].y + p[i].y + p[i + 1 ].y;
area = tarea(p[ 0 ],p[i],p[i + 1 ]);
sarea += area;
sumx += temp.x * area;
sumy += temp.y * area;
}
zhong = point(sumx / sarea / 3 ,sumy / sarea / 3 );
for ( int i = 0 ;i < n;i ++ )
vec[i] = p[i] - zhong;
// rotate the gravity point
zhong = rotate(zhong,earth,gong);
// gongzhuan
for ( int i = 0 ;i < n;i ++ )
p[i] = vec[i] + zhong;
// zizhuan
for ( int i = 0 ;i < n;i ++ )
p[i] = rotate(p[i],zhong,zi);
sort(p,p + n,cmp);
if ( ! cmp(cutl,cutr))
swap(cutl,cutr);
point L = p[ 0 ],R = p[n - 1 ];
if ( ! cmp(L,R))
swap(L,R);
point xl,xr;
line LE = line(sun,L),RI = line(sun,R);
if (comp(multi(L,cutl,sun)) <= 0 )
xl = cutl;
else if (comp(multi(L,cutr,sun)) >= 0 )
xl = cutr;
else
arc(LE,xl);
if (comp(multi(R,cutl,sun)) <= 0 )
xr = cutl;
else if (comp(multi(R,cutr,sun)) >= 0 )
xr = cutr;
else
arc(RI,xr);
double len1 = len(cutl,cutr),len2 = len(xl,xr);
if (comp((L - sun).norm() - (xl - sun).norm()) > 0 || comp((R - sun).norm() - (xr - sun).norm()) > 0 )
len2 = 0 ;
double ans = len1 - len2;
printf( " %.2lf\n " ,ans);
}
}
#include < cstdio >
#include < cmath >
#include < cstring >
#include < algorithm >
#define maxn 105
using namespace std;
const double pi = acos( - 1.0 );
struct point
{
double x,y;
point(){}
point( double a, double b):x(a),y(b){}
point operator - ( const point & p)
{
return point(x - p.x,y - p.y);
}
point operator + ( const point & p)
{
return point(x + p.x,y + p.y);
}
double operator * ( const point & p)
{
return x * p.x + y * p.y;
}
double operator ^ ( const point & p)
{
return x * p.y - y * p.x;
}
double norm()
{
return sqrt(x * x + y * y);
}
}sun,earth,vec[maxn],p[maxn],cutl,cutr;
double multi(point a,point b,point o)
{
return (a - o) ^ (b - o);
}
double r;
int T1,T2,T;
int n;
const double eps = 1e - 6 ;
int comp( double x)
{
if (fabs(x) < eps)
return 0 ;
else if (x < - eps)
return - 1 ;
else
return 1 ;
}
point rotate(point a,point o, double theta)
{
point vec = a - o;
point to = point(vec.x * cos(theta) - vec.y * sin(theta),vec.x * sin(theta) + vec.y * cos(theta));
return o + to;
}
double tarea(point p0,point p1,point p2)
{
double k = p0.x * p1.y + p1.x * p2.y + p2.x * p0.y - p1.x * p0.y - p2.x * p1.y - p0.x * p2.y;
return k / 2 ;
}
bool cmp(point p,point q)
{
double t1 = atan2(p.y - sun.y,p.x - sun.x),t2 = atan2(q.y - sun.y,q.x - sun.x);
return (comp(t1 - t2) > 0 );
}
struct line
{
double a,b,c;
line(){}
line(point p,point q)
{
if (comp(p.x - q.x) == 0 )
{
a = 1.0 ;
b = 0.0 ;
c = - p.x;
}
else if (comp(p.y - q.y) == 0 )
{
a = 0.0 ;
b = 1.0 ;
c = - p.y;
}
else
{
a = 1.0 ;
b = - (p.x - q.x) / (p.y - q.y);
c = - (p.x + b * p.y);
}
}
};
bool arc(line llll,point & P)
{
double a = llll.a,b = llll.b,c = llll.c;
double A = b * b + 1 ,B = 2.0 * b * c + 2.0 * b * earth.x - 2.0 * earth.y,C = c * c + 2.0 * c * earth.x + earth.x * earth.x + earth.y * earth.y - r * r;
double det = B * B - 4.0 * A * C;
if (comp(det) < 0 )
return false ;
else if (comp(det) == 0 )
{
double x,y;
y = ( - B + sqrt(det)) / ( 2.0 * A);
x = - (b * y + c);
point w(x,y);
P = w;
return true ;
}
else
{
double y1 = ( - B + sqrt(det)) / ( 2.0 * A),y2 = ( - B - sqrt(det)) / ( 2.0 * A);
double x1 = - (b * y1 + c),x2 = - (b * y2 + c);
point w1(x1,y1),w2(x2,y2);
double dis1 = (w1 - sun).norm(),dis2 = (w2 - sun).norm();
if (comp(dis1 - dis2) > 0 )
P = w2;
else
P = w1;
return true ;
}
}
void calc()
{
double a,b,c;
a = (sun.y - earth.y) * (sun.y - earth.y) + (sun.x - earth.x) * (sun.x - earth.x);
b = - 2.0 * earth.y * ((sun.y - earth.y) * (sun.y - earth.y) + (sun.x - earth.x) * (sun.x - earth.x)) - 2.0 * r * r * (sun.y - earth.y);
c = r * r * r * r + 2.0 * r * r * (sun.y - earth.y) * earth.y - r * r * (sun.x - earth.x) * (sun.x - earth.x) + earth.y * earth.y * ((sun.y - earth.y) * (sun.y - earth.y) + (sun.x - earth.x) * (sun.x - earth.x));
double det = b * b - 4.0 * a * c;
double y1 = ( - b + sqrt(det)) / ( 2.0 * a),y2 = ( - b - sqrt(det)) / ( 2.0 * a);
double x1 = (r * r - (sun.y - earth.y) * (y1 - earth.y)) / (sun.x - earth.x) + earth.x;
double x2 = (r * r - (sun.y - earth.y) * (y2 - earth.y)) / (sun.x - earth.x) + earth.x;
cutl = point(x1,y1),cutr = point(x2,y2);
if ( ! cmp(cutl,cutr))
swap(cutl,cutr);
}
double len(point a,point b)
{
point vec1 = point(a - earth),vec2 = point(b - earth);
double value = (vec1 * vec2) / (vec1.norm() * vec2.norm());
if (comp(value - 1.0 ) >= 0 )
value = 1.0 ;
double theta = acos(value);
return r * theta;
}
int main()
{
while (scanf( " %lf %lf %lf %lf %lf " , & sun.x, & sun.y, & earth.x, & earth.y, & r) == 5 )
{
// calc arc
calc();
scanf( " %d %d %d %d " , & n, & T1, & T2, & T);
for ( int i = 0 ;i < n;i ++ )
{
double x,y;
scanf( " %lf %lf " , & x, & y);
p[i] = point(x,y);
}
int t1 = T % T1,t2 = T % T2;
double gong = 2.0 * pi * ( double )t1 / ( double )T1,zi = 2.0 * pi * ( double ) t2 / ( double ) T2;
point zhong,temp( 0 , 0 );
double area = 0 ,sumx = 0 ,sumy = 0 ,sarea = 0 ;
for ( int i = 1 ;i < n - 1 ;i ++ )
{
temp.x = p[ 0 ].x + p[i].x + p[i + 1 ].x;
temp.y = p[ 0 ].y + p[i].y + p[i + 1 ].y;
area = tarea(p[ 0 ],p[i],p[i + 1 ]);
sarea += area;
sumx += temp.x * area;
sumy += temp.y * area;
}
zhong = point(sumx / sarea / 3 ,sumy / sarea / 3 );
for ( int i = 0 ;i < n;i ++ )
vec[i] = p[i] - zhong;
// rotate the gravity point
zhong = rotate(zhong,earth,gong);
// gongzhuan
for ( int i = 0 ;i < n;i ++ )
p[i] = vec[i] + zhong;
// zizhuan
for ( int i = 0 ;i < n;i ++ )
p[i] = rotate(p[i],zhong,zi);
sort(p,p + n,cmp);
if ( ! cmp(cutl,cutr))
swap(cutl,cutr);
point L = p[ 0 ],R = p[n - 1 ];
if ( ! cmp(L,R))
swap(L,R);
point xl,xr;
line LE = line(sun,L),RI = line(sun,R);
if (comp(multi(L,cutl,sun)) <= 0 )
xl = cutl;
else if (comp(multi(L,cutr,sun)) >= 0 )
xl = cutr;
else
arc(LE,xl);
if (comp(multi(R,cutl,sun)) <= 0 )
xr = cutl;
else if (comp(multi(R,cutr,sun)) >= 0 )
xr = cutr;
else
arc(RI,xr);
double len1 = len(cutl,cutr),len2 = len(xl,xr);
if (comp((L - sun).norm() - (xl - sun).norm()) > 0 || comp((R - sun).norm() - (xr - sun).norm()) > 0 )
len2 = 0 ;
double ans = len1 - len2;
printf( " %.2lf\n " ,ans);
}
}
Down