计算几何(半平面交&&旋转卡壳)

先介绍个写的很好的blog ————Master_Chivu

[Poj 1113] 计算几何之凸包(一) {卷包裹算法}

http://www.cnblogs.com/Booble/archive/2011/02/28/1967179.html

http://www.cnblogs.com/Booble/archive/2011/03/10/1980089.html

[Poj 2187]计算几何之凸包(三) {旋转卡壳初步}

http://www.cnblogs.com/Booble/archive/2011/04/03/2004865.html

旋转卡壳是在上面blog里学到的。

半平面交是在http://apps.hi.baidu.com/share/detail/14889384学到的。

下面是我的模板。

ContractedBlock.gif ExpandedBlockStart.gif 2451(Halfe_Plane_Intersection
ca...POJ的RE提示WA。害我看了两天。以为自己模板又挂了 - -
===================================================================
if ( fabs(seg[i].angle - seg[i - 1 ].angle) > eps )
{

while (deq.size() >= 2 && cross(seg[i].sou,seg[i].tar,inter( * deq.begin() , * (deq.begin() + 1 ) )) < - eps)
deq.pop_front();
while (deq.size() >= 2 && cross(seg[i].sou,seg[i].tar,inter( * (deq.end() - 1 ), * (deq.end() - 2 ) ) ) < - eps )
deq.pop_back();
deq.push_front(seg[i]);
}
while (deq.size() > 2 && cross((deq.end() - 1 ) -> sou,(deq.end() - 1 ) -> tar,
inter(
* (deq.begin()), * (deq.begin() + 1 ) ) ) < - eps)
deq.pop_front();
while (deq.size() > 2 && cross( deq.begin() -> sou, deq.begin() -> tar,
inter(
* (deq.end() - 1 ), * (deq.end() - 2 ) ) ) < - eps )
deq.pop_back();

一直怀疑划线加粗句是废话,固然
- - 。去掉后能能毫无压力过掉。
====================================================================
#include
< iostream >
#include
< cstdio >
#include
< deque >
#include
< cmath >
#include
< algorithm >
#include
< cstdlib >
using namespace std;
const int N = 300000 ;
const int M = 300000 ;
const double eps = 1e - 6 ;
struct node
{
double x,y;
}poi[N],tmp1,tmp2,zero,tpoi[N];
struct SEG
{
node sou,tar;
double angle;
}seg[M];
deque
< SEG > deq;
int Test,n,cnt,flag;
double tmp,s;
double dot(node a,node b)
{
return a.x * b.x + a.y * b.y;
}
double cross(node a,node b,node c)
{
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
node inter( SEG a, SEG b)
{
double s1,s2,ts;
s1
= cross(a.sou,a.tar,b.sou);
s2
= cross(a.sou,a.tar,b.tar);
ts
= s1 - s2;
if (fabs(ts) < eps) { tmp1.x = 10001 ; tmp1.y = 10001 ; return tmp1; }
tmp1.x
= b.sou.x * ( - s2) / ts + b.tar.x * s1 / ts;
tmp1.y
= b.sou.y * ( - s2) / ts + b.tar.y * s1 / ts;
return tmp1;
}
bool cmp( const SEG & a, const SEG & b)
{
if ( fabs(a.angle - b.angle) < eps )
return cross(a.sou,a.tar,b.sou) < 0 ;
else
return a.angle < b.angle;

}
void Half_Plane_Intersection()
{
deq.clear();
deq.push_front(seg[
0 ]);
int tt = 1 ; while (fabs(seg[tt].angle - seg[tt - 1 ].angle) < eps) ++ tt;
deq.push_front(seg[tt]);
for ( int i = tt + 1 ;i < n; ++ i)
if ( fabs(seg[i].angle - seg[i - 1 ].angle) > eps )
{

while (deq.size() >= 2 && cross(seg[i].sou,seg[i].tar,inter( * deq.begin() , * (deq.begin() + 1 ) )) < - eps)
deq.pop_front();
while (deq.size() >= 2 && cross(seg[i].sou,seg[i].tar,inter( * (deq.end() - 1 ), * (deq.end() - 2 ) ) ) < - eps )
deq.pop_back();
deq.push_front(seg[i]);
}
while (deq.size() > 2 && cross((deq.end() - 1 ) -> sou,(deq.end() - 1 ) -> tar,
inter(
* (deq.begin()), * (deq.begin() + 1 ) ) ) < - eps)
deq.pop_front();
while (deq.size() > 2 && cross( deq.begin() -> sou, deq.begin() -> tar,
inter(
* (deq.end() - 1 ), * (deq.end() - 2 ) ) ) < - eps )
deq.pop_back();
cnt
= 0 ;
for ( deque < SEG > ::iterator it = deq.begin(); it != deq.end(); ++ it)
{
deque
< SEG > ::iterator itt = it + 1 ;
if (itt == deq.end() ) itt = deq.begin();
tpoi[cnt
++ ] = inter( * it , * itt );
}
s
= 0 ;
for ( int i = 0 ;i < cnt; ++ i)
s
+= tpoi[i].x * tpoi[(i + 1 ) % cnt].y - tpoi[(i + 1 ) % cnt].x * tpoi[i].y;
if ( s == 0 && cnt <= 2 ) puts( " 0.0 " );
else printf( " %.1lf\n " ,s /- 2 + eps);
}
void work()
{
cin
>> n;
for ( int i = 0 ;i < n; ++ i)
cin
>> seg[i].sou.x >> seg[i].sou.y >> seg[i].tar.x >> seg[i].tar.y;
seg[n].sou.x
= 0 ; seg[n].sou.y = 0 ; seg[n].tar.x = 10000 ; seg[n].tar.y = 0 ; ++ n;
seg[n].sou.x
= 10000 ; seg[n].sou.y = 0 ; seg[n].tar.x = 10000 ; seg[n].tar.y = 10000 ; ++ n;
seg[n].sou.x
= 10000 ; seg[n].sou.y = 10000 ; seg[n].tar.x = 0 ; seg[n].tar.y = 10000 ; ++ n;
seg[n].sou.x
= 0 ; seg[n].sou.y = 10000 ; seg[n].tar.x = 0 ; seg[n].tar.y = 0 ; ++ n;
for ( int i = 0 ;i < n; ++ i)
seg[i].angle
= atan2(seg[i].tar.y - seg[i].sou.y,seg[i].tar.x - seg[i].sou.x);
sort(seg,seg
+ n,cmp);
Half_Plane_Intersection();
}
int main()
{
work();
return 0 ;
}

下面是旋转卡壳模板

ContractedBlock.gif ExpandedBlockStart.gifPOJ3608  旋转卡壳
给你两个不想交的凸包 ~ 求两个凸包间的最短距离。
旋转卡壳模板题。
====================================================================================
int change_angle( int tp1, int tp2, double & ang)
{
double ang1,ang2,a1,a2;
ang1
= atan2( HullA[ (tp1 + 1 ) % cnta ].y - HullA[ tp1 ].y , HullA[ (tp1 + 1 ) % cnta ].x - HullA[ tp1 ].x);
if (ang1 < 0 ) ang1 = 2 * pi + ang1;
a1
= ang1 - ang; if (a1 < 0 ) a1 += 2 * pi;
ang2
= atan2( - (HullB[ (tp2 + 1 ) % cnta ].y - HullB[ tp2 ].y) , - (HullB[ (tp2 + 1 ) % cntb ].x - HullB[ tp2 ].x));
if (ang2 < 0 ) ang2 = 2 * pi + ang2;
a2
= ang2 - ang; if (a2 < 0 ) a2 += 2 * pi;
if ( fabs( a1 - a2 ) < eps ){ ang = ang1; return 2 ;}
if ( a1 < a2 ) {ang = ang1; return 0 ;} else {ang = ang2; return 1 ;}
}
计算平行线下一次跟哪边相贴。
返回1跟A ,返回
2 跟B相贴,返回3,同时相贴。

=====================================================================================
while (flag < (n + m) * 5 )
{
tmp
= change_angle(tp1,tp2,ang);
ans
= min( ans , dis(HullB[tp2],HullB[(tp2 + 1 ) % cntb],HullA[tp1]) );
ans
= min( ans , dis(HullB[tp2],HullB[(tp2 + 1 ) % cntb],HullA[(tp1 + 1 ) % cnta]) );
ans
= min( ans ,dis(HullA[tp1], HullA[(tp1 + 1 ) % cnta], HullB[tp2] ) );
ans
= min( ans ,dis(HullA[tp1], HullA[(tp1 + 1 ) % cnta], HullB[(tp2 + 1 ) % cntb] ) );
if (tmp == 0 )
tp1
= (tp1 + 1 ) % cnta;
else if (tmp == 1 )
tp2
= (tp2 + 1 ) % cntb;
else
{
tp1
= (tp1 + 1 ) % cnta;
tp2
= (tp2 + 1 ) % cntb;
}
++ flag;
}
旋转卡壳主过程
~ 每次判断当前两条平行线所在凸包边的四个点两两之间距离。 旋转之 ~
不要偷懒,还是每次都比较四个点比较保险
- - 。通常不会卡这点常数 ~
旋转次数嘛
~ 多点就好了。
angle转360就可以了吧。偷懒下。。。
============================================================================================


#include
< iostream >
#include
< cstdio >
#include
< cmath >
#include
< algorithm >
using namespace std;
const double pi = acos( - 1.0 );
double ans;
const int N = 100000 ;
const double eps = 1e - 8 ;
int n,cnt,cnta,cntb,tp,m,tmp,tp1,tp2;
struct node
{
double x,y;
} HullA[N],p[N],HullB[N],Hull[N];
double cross(node a,node b, node c)
{
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
bool cmp( const node & a , const node & b)
{
if (a.y == b.y ) return a.x < b.x;
return a.y < b.y;
}
double dis(node a,node b)
{
return sqrt( (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) );
}
double dot(node a,node b,node c)
{
return (b.x - a.x) * (c.x - a.x) + (b.y - a.y) * (c.y - a.y);
}
double dis(node a,node b, node c)
{
if (dot(a,b,c) < 0 || dot(b,a,c) < 0 ) return min(dis(a,c) , dis(b,c) );
return fabs( cross(a,b,c) ) / dis(a,b);
}
void Calc_Hull( int n)
{
for ( int i = 0 ;i < n; ++ i)
cin
>> p[i].x >> p[i].y;
sort(p,p
+ n,cmp);
cnt
= 0 ;
for ( int i = 0 ;i < n; ++ i)
{
while (cnt > 1 && cross(Hull[cnt - 2 ],Hull[cnt - 1 ],p[i]) < eps ) cnt -- ;
Hull[cnt
++ ] = p[i];
}
int t = cnt;
for ( int i = n - 1 ;i >= 0 ;i -- )
{
while (cnt > t && cross(Hull[cnt - 2 ],Hull[cnt - 1 ],p[i]) < eps) cnt -- ;
Hull[cnt
++ ] = p[i];
}
-- cnt;
}
int change_angle( int tp1, int tp2, double & ang)
{
double ang1,ang2,a1,a2;
ang1
= atan2( HullA[ (tp1 + 1 ) % cnta ].y - HullA[ tp1 ].y , HullA[ (tp1 + 1 ) % cnta ].x - HullA[ tp1 ].x);
if (ang1 < 0 ) ang1 = 2 * pi + ang1;
a1
= ang1 - ang; if (a1 < 0 ) a1 += 2 * pi;
ang2
= atan2( - (HullB[ (tp2 + 1 ) % cnta ].y - HullB[ tp2 ].y) , - (HullB[ (tp2 + 1 ) % cntb ].x - HullB[ tp2 ].x));
if (ang2 < 0 ) ang2 = 2 * pi + ang2;
a2
= ang2 - ang; if (a2 < 0 ) a2 += 2 * pi;
if ( fabs( a1 - a2 ) < eps ){ ang = ang1; return 2 ;}
if ( a1 < a2 ) {ang = ang1; return 0 ;} else {ang = ang2; return 1 ;}
}
int main()
{
int Test = 0 ;
while (cin >> n >> m)
{
if (n == 0 ) break ;
Calc_Hull(n);
cnta
= cnt;
for ( int i = 0 ;i < cnta; ++ i) HullA[i] = Hull[i];
Calc_Hull(m);
cntb
= cnt;
for ( int i = 0 ;i < cntb; ++ i) HullB[i] = Hull[i];
tp1
= 0 ;tp2 = 0 ;
for ( int i = 1 ;i < cntb; ++ i) if ( ! cmp(HullB[i],HullB[tp2]) ) tp2 = i;
ans
= dis( HullA[ 0 ], HullB[tp2] );
int flag = 0 ;
double ang = 0 ;
while (flag < (n + m) * 5 )
{
tmp
= change_angle(tp1,tp2,ang);
ans
= min( ans , dis(HullB[tp2],HullB[(tp2 + 1 ) % cntb],HullA[tp1]) );
ans
= min( ans , dis(HullB[tp2],HullB[(tp2 + 1 ) % cntb],HullA[(tp1 + 1 ) % cnta]) );
ans
= min( ans ,dis(HullA[tp1], HullA[(tp1 + 1 ) % cnta], HullB[tp2] ) );
ans
= min( ans ,dis(HullA[tp1], HullA[(tp1 + 1 ) % cnta], HullB[(tp2 + 1 ) % cntb] ) );
if (tmp == 0 )
tp1
= (tp1 + 1 ) % cnta;
else if (tmp == 1 )
tp2
= (tp2 + 1 ) % cntb;
else
{
tp1
= (tp1 + 1 ) % cnta;
tp2
= (tp2 + 1 ) % cntb;
}
++ flag;
}
printf(
" %.5lf\n " ,ans);
}
return 0 ;
}

转载于:https://www.cnblogs.com/LitIce/archive/2011/04/09/2010180.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值