??xml version="1.0" encoding="utf-8" standalone="yes"?>
因ؓ所有简单多边Ş都可切割Z?a title=三角?>三角?/font>和另一个简单多边Ş。考虑一个简单多边ŞPQ及?em>P有一条共同边的三角ŞT。若PW合皮克公式Q则只要证明P加上T?em>PT亦符合皮克公式(IQ,与及三角形符合皮克公式(IIQ,可Ҏ数学归纳?/font>Q对于所有简单多边Ş皮克公式都是成立的?
?em>P?em>T的共同边上有c个格炏V?
证明分三部分Q证明以下的囑ŞW合皮克定理Q?
讄?em>R长边短边各有m,n个格点:
易见两条邻边?a title=角R?>对角U?/font>l成的两个直角三角Ş全等Q且i,b相等。设其斜边上?em>c个格炏V?
Georg Alexander PickQ?a title=1859q?>1859q?/font>生于l也U?/font>Q?a title=1943q?>1943q?/font>M特莱西恩施塔牚w中营?
en:Pick's theorem fr:Théorème de Pick it:Teorema di Pick pl:Wzór Picka ru:Теорема Пиaа
判断Ҏ否在U段上:
讄为QQ线DؓP1P2 Q判断点Q在该U段上的依据是:( Q - P1 ) × ( P2 - P1 ) = 0 ?Q 在以 P1QP2为对角顶点的矩Ş内。前者保证Q点在直线P1P2上,后者是保证Q点不在线DP1P2的g长线或反向g长线上,对于q一步骤的判断可以用以下q程实现Q?br>
ON-SEGMENT(pi,pj,pk)
if min(xi,xj)<=xk<=max(xi,xj) and min(yi,yj)<=yk<=max(yi,yj)
then return true;
else return false;
特别要注意的是,׃需要考虑水^U段和垂直线D两U特D情况,min(xi,xj)<=xk<=max(xi,xj)和min(yi,yj)<=yk<=max(yi,yj)两个条g必须同时满才能q回真倹{?br>
判断两线D|否相交:
我们分两步确定两条线D|否相交:
(1)快速排斥试?br>
设以U段 P1P2 为对角线的矩形ؓRQ?设以U段 Q1Q2 为对角线的矩形ؓTQ如果R和T不相交,昄两线D不会相交?br>
(2)跨立试验
如果两线D늛交,则两U段必然怺跨立Ҏ。若P1P2跨立Q1Q2 Q则矢量 ( P1 - Q1 ) ? P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,? P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写? P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 Ӟ说明 ( P1 - Q1 ) ?( Q2 - Q1 )qQ但是因为已l通过快速排斥试验,所?P1 一定在U段 Q1Q2上;同理Q? Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在U段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是Q? P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是Q? Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。具体情况如下图所C:
在相同的原理下,Ҏ法的具体的实现l节可能会与此有所不同Q除了这U过E外Q大家也可以参考《算法导论》上的实现?br> Zl一赯Q我们在计算线L和多边Ş的交点的时候,1。对于多边Ş的水q不作考虑Q?。对于多边Ş的顶点和L怺的情况,如果该顶Ҏ其所属的边上U坐标较大的点Q则计数Q否则忽略;3。对于P在多边Ş边上的情形,直接可判断P属于多边行。由此得出算法的伪代码如下: 因此我们可以先求出所有和U段怺的多边Ş的顶点,然后按照X-Y坐标排序(X坐标的排在前面Q对于X坐标相同的点QY坐标的排在前面Q这U排序准则也是ؓ了保证水q_垂直情况的判断正?Q这Lȝ两个点就是在U段上相ȝ两交点,如果L盔R两点的中点也在多边Ş内,则该U段一定在多边形内? 计算U段或直U与U段的交? 凸包的求法:
判断U段和直U是否相交:
有了上面的基Q这个算法就很容易了。如果线DP1P2和直UQ1Q2怺Q则P1P2跨立Q1Q2Q即Q? P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0?br>
判断矩Ş是否包含点:
只要判断该点的横坐标和纵坐标是否夹在矩Ş的左双和上下边之间?br>
判断U段、折Uѝ多边Ş是否在矩形中Q?/strong>
因ؓ矩Ş是个凔RQ所以只要判断所有端Ҏ否都在矩形中可以了?br>
判断矩Ş是否在矩形中Q?/strong>
只要比较左右边界和上下边界就可以了?br>
判断圆是否在矩Ş中:
很容易证明,圆在矩Ş中的充要条g是:圆心在矩形中且圆的半径小于等于圆心到矩Ş四边的距ȝ最倹{?br>
判断Ҏ否在多边形中Q?/strong>
判断点P是否在多边Ş中是计算几何中一个非常基本但是十分重要的法。以点P为端点,向左方作线LQ由于多边Ş是有界的Q所以射UL的左端一定在多边形外Q考虑沿着L从无I处开始自左向右移动,遇到和多边Ş的第一个交点的时候,q入C多边形的内部Q遇到第二个交点的时候,d了多边ŞQ?#8230;…所以很Ҏ看出当L和多边Ş的交Ҏ目C是奇数的时候,P在多边Ş内,是偶数的话P在多边Ş外?br>
但是有些Ҏ情况要加以考虑。如图下?a)(b)(c)(d)所C。在?a)中,L和多边Ş的顶点相交,q时候交点只能计一个;在图(b)中,L和多边Ş点的交点不应被计算Q在?c)?d) 中,L和多边Ş的一条边重合Q这条边应该被忽略不计。如果L和多边Ş的一条边重合Q这条边应该被忽略不计?/p>
count ← 0;
以P为端点,作从叛_左的线L;
for 多边形的每条边s
do if P在边s?
then return true;
if s不是水^?br> then if s的一个端点在L?br> if 该端Ҏs两端点中U坐标较大的端点
then count ← count+1
else if s和L怺
then count ← count+1;
if count mod 2 = 1
then return true;
else return false;
其中做射UL的方法是Q设P'的纵坐标和P相同Q横坐标为正无穷大(很大的一个正敎ͼQ则P和P'q定了线L?
判断Ҏ否在多边形中的这个算法的旉复杂度ؓO(n)?br>
另外q有一U算法是用带W号的三角Ş面积之和与多边Ş面积q行比较Q这U算法由于用QҎq算所以会带来一定误差,不推荐大家用?
判断U段是否在多边Ş内:
U段在多边Ş内的一个必要条件是U段的两个端炚w在多边Ş内,但由于多边Ş可能为凹Q所以这不能成ؓ判断的充分条件。如果线D和多边形的某条边内交(两线D内交是指两U段怺且交点不在两U段的端点)Q因为多边Ş的边的左右两侧分属多边Ş内外不同部分Q所以线D一定会有一部分在多边Ş?见图a)。于是我们得到线D在多边形内的第二个必要条gQ线D和多边形的所有边都不内交?
U段和多边Ş交于U段的两端点q不会媄响线D|否在多边形内Q但是如果多边Ş的某个顶点和U段怺Q还必须判断两相M点之间的U段是否包含于多边Ş内部Q反例见图b)?/p>
证明如下Q?br>
命题1Q?br>
如果U段和多边Ş的两盔R交点P1 QP2的中点P' 也在多边形内Q则P1, P2之间的所有点都在多边形内?br>
证明Q?br>
假设P1,P2之间含有不在多边形内的点Q不妨设该点为QQ在P1, P'之间Q因为多边Ş是闭合曲U,所以其内外部之间有界,而P1属于多边行内部,Q属于多边性外部,P'属于多边性内部,P1-Q-P'完全q箋Q所以P1Q和QP'一定跨多边Ş的边界,因此在P1,P'之间臛_q有两个该线D和多边形的交点Q这和P1P2是相M交点矛盾Q故命题成立。证毕?
由命?直接可得出推论:
推论2Q?br>
讑֤边Ş和线DPQ的交点依ơؓP1,P2,……PnQ其中Pi和Pi+1是相M交点Q线DPQ在多边Ş内的充要条g是:PQQ在多边Ş内且对于i =1, 2,……, n-1QPi ,Pi+1的中点也在多边Ş内?br>
在实际编E中Q没有必要计所有的交点Q首先应判断U段和多边Ş的边是否内交Q倘若U段和多边Ş的某条边内交则线D一定在多边形外Q如果线D和多边形的每一条边都不内交Q则U段和多边Ş的交点一定是U段的端Ҏ者多边Ş的顶点,只要判断Ҏ否在U段上就可以了?br>
x我们得出法如下Q?br>
if U端PQ的端点不都在多边形内
then return false;
炚wpointSet初始化ؓI?
for 多边形的每条边s
do if U段的某个端点在s?br> then 该端点加入pointSet;
else if s的某个端点在U段PQ?br> then 该端点加入pointSet;
else if s和线DPQ怺 // q时候已l可以肯定是内交?br> then return false;
pointSet中的Ҏ照X-Y坐标排序;
for pointSet中每两个盔R?pointSet[i] , pointSet[ i+1]
do if pointSet[i] , pointSet[ i+1] 的中点不在多边Ş?br> then return false;
return true;
q个q程中的排序因ؓ交点数目肯定q小于多边Ş的顶Ҏ目nQ所以最多是常数U的复杂度,几乎可以忽略不计。因此算法的旉复杂度也是O(n)?
判断折线是否在多边Ş内:
只要判断折线的每条线D|否都在多边Ş内即可。设折线有m条线D,多边形有n个顶点,则该法的时间复杂度为O(m*n)?
判断多边形是否在多边形内Q?
只要判断多边形的每条Ҏ否都在多边Ş内即可。判断一个有m个顶点的多边形是否在一个有n个顶点的多边形内复杂度ؓO(m*n)?br>
判断矩Ş是否在多边Ş内:
矩形{化ؓ多边形,然后再判断是否在多边形内?
判断圆是否在多边形内Q?/strong>
只要计算圆心到多边Ş的每条边的最短距,如果该距d于等于圆半径则该圆在多边形内。计圆心到多边形每条边最短距ȝ法在后文阐q?
判断Ҏ否在圆内Q?/strong>
计算圆心到该点的距离Q如果小于等于半径则该点在圆内?br>
判断U段、折Uѝ矩形、多边Ş是否在圆?
因ؓ圆是凔RQ所以只要判断是否每个顶炚w在圆内即可?
判断圆是否在圆内Q?/strong>
设两圆ؓO1,O2Q半径分别ؓr1, r2Q要判断O2是否在O1内。先比较r1Qr2的大,如果r1<r2则O2不可能在O1内;否则如果两圆心的距离大于r1 - r2 Q则O2不在O1内;否则O2在O1内?
计算点到U段的最q点Q?/strong>
如果该线D^行于X_Y_Q则q点point作该U段所在直U的垂线Q垂_Ҏ求得Q然后计出垂Q如果垂_U段上则q回垂Q否则返回离垂q的端点Q如果该U段不^行于X轴也不^行于Y_则斜率存在且不ؓ0。设U段的两端点为pt1和pt2Q斜率ؓQk = ( pt2.y - pt1. y ) / (pt2.x - pt1.x );该直U方EؓQy = k* ( x - pt1.x) + pt1.y。其垂线的斜率ؓ - 1 / kQ垂U方EؓQy = (-1/k) * (x - point.x) + point.y ?
联立两直U方E解得:x = ( k^2 * pt1.x + k * (point.y - pt1.y ) + point.x ) / ( k^2 + 1) Qy = k * ( x - pt1.x) + pt1.y;然后再判断垂x否在U段上,如果在线D上则返回垂I如果不在则计两端点到垂的距离Q选择距离垂较近的端点返回?
计算点到折线、矩形、多边Ş的最q点Q?/strong>
只要分别计算点到每条U段的最q点Q记录最q距,取其中最q距L的点即可?
计算点到圆的最q距d交点坐标Q?/strong>
如果该点在圆心,因ؓ圆心到圆周Q一点的距离相等Q返回UNDEFINED?
q接点P和圆心OQ如果POq于X_则根据P在O的左边还是右边计出最q点的横坐标为centerPoint.x - radius ?centerPoint.x + radius。如果POq于Y_则根据P在O的上边还是下边计出最q点的纵坐标?centerPoint.y -+radius?centerPoint.y - radius。如果PO不^行于X轴和Y_则PO的斜率存在且不ؓ0Q这时直UPO斜率为k = Q?P.y - O.y Q? ( P.x - O.x )。直UPO的方EؓQy = k * ( x - P.x) + P.y。设圆方Eؓ:(x - O.x ) ^2 + ( y - O.y ) ^2 = r ^2Q联立两方程l可以解出直UPO和圆的交点,取其中离P点较q的交点卛_?
计算两条q的线D늚交点Q?/strong>
对于两条q的线D,它们之间的位|关pL下图所C的几种情况。图(a)中两条线D|有交点;?(b) ?(d) 中两条线D|无穷焦点Q图 (c) 中两条线D|一个交炏V设line1是两条线D中较长的一条,line2是较短的一条,如果line1包含了line2的两个端点,则是?d)的情况,两线D|无穷交点Q如果line1只包含line2的一个端点,那么如果line1的某个端点等于被line1包含的line2的那个端点,则是?c)的情况,q时两线D只有一个交点,否则是?b)的情况,两线D也是有无穷的交点;如果line1不包含line2的Q何端点,则是?a)的情况,q时两线D|有交炏V?/p>
设一条线DؓL0 = P1P2Q另一条线D|直线为L1 = Q1Q2 Q要计算的就是L0和L1的交炏V?br>
1Q?首先判断L0和L1是否怺Q方法已在前文讨Q,如果不相交则没有交点Q否则说明L0和L1一定有交点Q下面就L0和L1都看作直U来考虑?
2Q?如果P1和P2横坐标相同,即L0q于Y?
a) 若L1也^行于Y_
i. 若P1的纵坐标和Q1的纵坐标相同Q说明L0和L1qQ假如L1是直U的话他们有无穷的交点,假如L1是线D늚话可?计算两条qU段的交?的算法求他们的交点(该方法在前文已讨Q;
ii. 否则说明L0和L1qQ他们没有交点;
b) 若L1不^行于Y_则交Ҏ坐标为P1的横坐标Q代入到L1的直U方E中可以计算Z点纵坐标Q?
3Q?如果P1和P2横坐标不同,但是Q1和Q2横坐标相同,即L1q于Y_则交Ҏ坐标为Q1的横坐标Q代入到L0的直U方E中可以计算Z点纵坐标Q?
4Q?如果P1和P2U坐标相同,即L0q于X?
a) 若L1也^行于X_
i. 若P1的横坐标和Q1的横坐标相同Q说明L0和L1qQ假如L1是直U的话他们有无穷的交点,假如L1是线D늚话可?计算两条qU段的交?的算法求他们的交点(该方法在前文已讨Q;
ii. 否则说明L0和L1qQ他们没有交点;
b) 若L1不^行于X_则交点纵坐标为P1的纵坐标Q代入到L1的直U方E中可以计算ZҎ坐标Q?
5Q?如果P1和P2U坐标不同,但是Q1和Q2U坐标相同,即L1q于X_则交点纵坐标为Q1的纵坐标Q代入到L0的直U方E中可以计算ZҎ坐标Q?
6Q?剩下的情况就是L1和L0的斜率均存在且不?的情?
a) 计算出L0的斜率K0QL1的斜率K1 Q?
b) 如果K1 = K2
i. 如果Q1在L0上,则说明L0和L1qQ假如L1是直U的话有无穷交点Q假如L1是线D늚话可?计算两条qU段的交?的算法求他们的交点(该方法在前文已讨Q;
ii. 如果Q1不在L0上,则说明L0和L1qQ他们没有交炏V?br>
c) 联立两直U的方程l可以解ZҎ
q个法q不复杂Q但是要分情况讨论清楚,其是当两条U段q的情况需要单独考虑Q所以在前文求两条qU段的算法单独写出来。另外,一开始就先利用矢量叉乘判断线D与U段Q或直线Q是否相交,如果l果是相交,那么在后面就可以线D全部看作直U来考虑。需要注意的是,我们可以直U或U段方程改写为ax+by+c=0的Ş式,q样一来上q过E的部分步骤可以合ƈQ羃短了代码长度Q但是由于先要求出参敎ͼq种法花Ҏ多的旉?
求线D|直线与折Uѝ矩形、多边Ş的交点:
分别求与每条边的交点卛_?
求线D|直线与圆的交?
讑֜心ؓOQ圆半径为rQ直U(或线D)L上的两点为P1,P2?
1. 如果L是线D且P1QP2都包含在圆O内,则没有交点;否则q行下一步?
2. 如果Lq于Y_
a) 计算圆心到L的距disQ?br> b) 如果dis > r 则L和圆没有交点Q?br> c) 利用勾股定理Q可以求Z交点坐标Q但要注意考虑L和圆的相切情c?br>
3. 如果Lq于X_做法与Lq于Y轴的情况cMQ?
4. 如果L既不qX轴也不^行Y_可以求出L的斜率KQ然后列出L的点斜式方程Q和圆方E联立即可求解出L和圆的两个交点;
5. 如果L是线D,对于2Q?Q?中求出的交点q要分别判断是否属于该线D늚范围内?
凸包的概念:
炚wQ的凸?convex hull)是指一个最凸多边形,满Q中的Ҏ者在多边形边上或者在其内。下图中q色线D表C的多边形就是点集Q={p0,p1,...p12}的凸包?/p>
现在已经证明了凸包算法的旉复杂度下界是O(n*logn),但是当凸包的点数h也被考虑q去的话QKrikpatrick和Seidel的剪枝搜索算法可以达到O(n*logh)Q在渐进意义下达到最优。最常用的凸包算法是Graham扫描法和Jarvis步进法。本文只单介l一下Graham扫描法,其正性的证明和Jarvis步进法的q程大家可以参考《算法导论》?
对于一个有三个或以上点的点集QQGraham扫描法的q程如下Q?
令p0为Q中Y-X坐标排序下最的?
?lt;p1,p2,...pm>为对其余Ҏ以p0Z心的极角逆时针排序所得的炚wQ如果有多个Ҏ相同的极角,除了距p0最q的点外全部U除
压p0q栈S
压p1q栈S
压p2q栈S
for i ← 3 to m
do while 由S的栈元素的下一个元素、S的栈元素以及pi构成的折U段不拐向左?br> 对SҎ
压piq栈S
return S;
此过E执行后Q栈S由底至顶的元素就是Q的凸包顶Ҏ逆时针排列的点序列。需要注意的是,我们对点按极角逆时针排序时Qƈ不需要真正求出极角,只需要求ZQ意两点的ơ序可以了。而这个步骤可以用前述的矢量叉U性质实现?
四、结?/strong>
管人类对几何学的研I从古代起便没有中断q,但是具体到借助计算机来解决几何问题的研IӞq只是停留在一个初U阶D,无论从应用领域还是发展前景来看,计算几何学都值得我们认真学习、加以运用,希望q篇文章能带你走q这个丰富多彩的世界?/p>
判断Ҏ否在U段上:
讄为QQ线DؓP1P2 Q判断点Q在该U段上的依据是:( Q - P1 ) × ( P2 - P1 ) = 0 ?Q 在以 P1QP2为对角顶点的矩Ş内。前者保证Q点在直线P1P2上,后者是保证Q点不在线DP1P2的g长线或反向g长线上,对于q一步骤的判断可以用以下q程实现Q?br>
ON-SEGMENT(pi,pj,pk)
if min(xi,xj)<=xk<=max(xi,xj) and min(yi,yj)<=yk<=max(yi,yj)
then return true;
else return false;
特别要注意的是,׃需要考虑水^U段和垂直线D两U特D情况,min(xi,xj)<=xk<=max(xi,xj)和min(yi,yj)<=yk<=max(yi,yj)两个条g必须同时满才能q回真倹{?br>
判断两线D|否相交:
我们分两步确定两条线D|否相交:
(1)快速排斥试?br>
设以U段 P1P2 为对角线的矩形ؓRQ?设以U段 Q1Q2 为对角线的矩形ؓTQ如果R和T不相交,昄两线D不会相交?br>
(2)跨立试验
如果两线D늛交,则两U段必然怺跨立Ҏ。若P1P2跨立Q1Q2 Q则矢量 ( P1 - Q1 ) ? P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,? P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写? P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 Ӟ说明 ( P1 - Q1 ) ?( Q2 - Q1 )qQ但是因为已l通过快速排斥试验,所?P1 一定在U段 Q1Q2上;同理Q? Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在U段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是Q? P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是Q? Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。具体情况如下图所C:
在相同的原理下,Ҏ法的具体的实现l节可能会与此有所不同Q除了这U过E外Q大家也可以参考《算法导论》上的实现?br> Zl一赯Q我们在计算线L和多边Ş的交点的时候,1。对于多边Ş的水q不作考虑Q?。对于多边Ş的顶点和L怺的情况,如果该顶Ҏ其所属的边上U坐标较大的点Q则计数Q否则忽略;3。对于P在多边Ş边上的情形,直接可判断P属于多边行。由此得出算法的伪代码如下: 因此我们可以先求出所有和U段怺的多边Ş的顶点,然后按照X-Y坐标排序(X坐标的排在前面Q对于X坐标相同的点QY坐标的排在前面Q这U排序准则也是ؓ了保证水q_垂直情况的判断正?Q这Lȝ两个点就是在U段上相ȝ两交点,如果L盔R两点的中点也在多边Ş内,则该U段一定在多边形内? 计算U段或直U与U段的交? 凸包的求法:
判断U段和直U是否相交:
有了上面的基Q这个算法就很容易了。如果线DP1P2和直UQ1Q2怺Q则P1P2跨立Q1Q2Q即Q? P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0?br>
判断矩Ş是否包含点:
只要判断该点的横坐标和纵坐标是否夹在矩Ş的左双和上下边之间?br>
判断U段、折Uѝ多边Ş是否在矩形中Q?/strong>
因ؓ矩Ş是个凔RQ所以只要判断所有端Ҏ否都在矩形中可以了?br>
判断矩Ş是否在矩形中Q?/strong>
只要比较左右边界和上下边界就可以了?br>
判断圆是否在矩Ş中:
很容易证明,圆在矩Ş中的充要条g是:圆心在矩形中且圆的半径小于等于圆心到矩Ş四边的距ȝ最倹{?br>
判断Ҏ否在多边形中Q?/strong>
判断点P是否在多边Ş中是计算几何中一个非常基本但是十分重要的法。以点P为端点,向左方作线LQ由于多边Ş是有界的Q所以射UL的左端一定在多边形外Q考虑沿着L从无I处开始自左向右移动,遇到和多边Ş的第一个交点的时候,q入C多边形的内部Q遇到第二个交点的时候,d了多边ŞQ?#8230;…所以很Ҏ看出当L和多边Ş的交Ҏ目C是奇数的时候,P在多边Ş内,是偶数的话P在多边Ş外?br>
但是有些Ҏ情况要加以考虑。如图下?a)(b)(c)(d)所C。在?a)中,L和多边Ş的顶点相交,q时候交点只能计一个;在图(b)中,L和多边Ş点的交点不应被计算Q在?c)?d) 中,L和多边Ş的一条边重合Q这条边应该被忽略不计。如果L和多边Ş的一条边重合Q这条边应该被忽略不计?/p>
count ← 0;
以P为端点,作从叛_左的线L;
for 多边形的每条边s
do if P在边s?
then return true;
if s不是水^?br> then if s的一个端点在L?br> if 该端Ҏs两端点中U坐标较大的端点
then count ← count+1
else if s和L怺
then count ← count+1;
if count mod 2 = 1
then return true;
else return false;
其中做射UL的方法是Q设P'的纵坐标和P相同Q横坐标为正无穷大(很大的一个正敎ͼQ则P和P'q定了线L?
判断Ҏ否在多边形中的这个算法的旉复杂度ؓO(n)?br>
另外q有一U算法是用带W号的三角Ş面积之和与多边Ş面积q行比较Q这U算法由于用QҎq算所以会带来一定误差,不推荐大家用?
判断U段是否在多边Ş内:
U段在多边Ş内的一个必要条件是U段的两个端炚w在多边Ş内,但由于多边Ş可能为凹Q所以这不能成ؓ判断的充分条件。如果线D和多边形的某条边内交(两线D内交是指两U段怺且交点不在两U段的端点)Q因为多边Ş的边的左右两侧分属多边Ş内外不同部分Q所以线D一定会有一部分在多边Ş?见图a)。于是我们得到线D在多边形内的第二个必要条gQ线D和多边形的所有边都不内交?
U段和多边Ş交于U段的两端点q不会媄响线D|否在多边形内Q但是如果多边Ş的某个顶点和U段怺Q还必须判断两相M点之间的U段是否包含于多边Ş内部Q反例见图b)?/p>
证明如下Q?br>
命题1Q?br>
如果U段和多边Ş的两盔R交点P1 QP2的中点P' 也在多边形内Q则P1, P2之间的所有点都在多边形内?br>
证明Q?br>
假设P1,P2之间含有不在多边形内的点Q不妨设该点为QQ在P1, P'之间Q因为多边Ş是闭合曲U,所以其内外部之间有界,而P1属于多边行内部,Q属于多边性外部,P'属于多边性内部,P1-Q-P'完全q箋Q所以P1Q和QP'一定跨多边Ş的边界,因此在P1,P'之间臛_q有两个该线D和多边形的交点Q这和P1P2是相M交点矛盾Q故命题成立。证毕?
由命?直接可得出推论:
推论2Q?br>
讑֤边Ş和线DPQ的交点依ơؓP1,P2,……PnQ其中Pi和Pi+1是相M交点Q线DPQ在多边Ş内的充要条g是:PQQ在多边Ş内且对于i =1, 2,……, n-1QPi ,Pi+1的中点也在多边Ş内?br>
在实际编E中Q没有必要计所有的交点Q首先应判断U段和多边Ş的边是否内交Q倘若U段和多边Ş的某条边内交则线D一定在多边形外Q如果线D和多边形的每一条边都不内交Q则U段和多边Ş的交点一定是U段的端Ҏ者多边Ş的顶点,只要判断Ҏ否在U段上就可以了?br>
x我们得出法如下Q?br>
if U端PQ的端点不都在多边形内
then return false;
炚wpointSet初始化ؓI?
for 多边形的每条边s
do if U段的某个端点在s?br> then 该端点加入pointSet;
else if s的某个端点在U段PQ?br> then 该端点加入pointSet;
else if s和线DPQ怺 // q时候已l可以肯定是内交?br> then return false;
pointSet中的Ҏ照X-Y坐标排序;
for pointSet中每两个盔R?pointSet[i] , pointSet[ i+1]
do if pointSet[i] , pointSet[ i+1] 的中点不在多边Ş?br> then return false;
return true;
q个q程中的排序因ؓ交点数目肯定q小于多边Ş的顶Ҏ目nQ所以最多是常数U的复杂度,几乎可以忽略不计。因此算法的旉复杂度也是O(n)?
判断折线是否在多边Ş内:
只要判断折线的每条线D|否都在多边Ş内即可。设折线有m条线D,多边形有n个顶点,则该法的时间复杂度为O(m*n)?
判断多边形是否在多边形内Q?
只要判断多边形的每条Ҏ否都在多边Ş内即可。判断一个有m个顶点的多边形是否在一个有n个顶点的多边形内复杂度ؓO(m*n)?br>
判断矩Ş是否在多边Ş内:
矩形{化ؓ多边形,然后再判断是否在多边形内?
判断圆是否在多边形内Q?/strong>
只要计算圆心到多边Ş的每条边的最短距,如果该距d于等于圆半径则该圆在多边形内。计圆心到多边形每条边最短距ȝ法在后文阐q?
判断Ҏ否在圆内Q?/strong>
计算圆心到该点的距离Q如果小于等于半径则该点在圆内?br>
判断U段、折Uѝ矩形、多边Ş是否在圆?
因ؓ圆是凔RQ所以只要判断是否每个顶炚w在圆内即可?
判断圆是否在圆内Q?/strong>
设两圆ؓO1,O2Q半径分别ؓr1, r2Q要判断O2是否在O1内。先比较r1Qr2的大,如果r1<r2则O2不可能在O1内;否则如果两圆心的距离大于r1 - r2 Q则O2不在O1内;否则O2在O1内?
计算点到U段的最q点Q?/strong>
如果该线D^行于X_Y_Q则q点point作该U段所在直U的垂线Q垂_Ҏ求得Q然后计出垂Q如果垂_U段上则q回垂Q否则返回离垂q的端点Q如果该U段不^行于X轴也不^行于Y_则斜率存在且不ؓ0。设U段的两端点为pt1和pt2Q斜率ؓQk = ( pt2.y - pt1. y ) / (pt2.x - pt1.x );该直U方EؓQy = k* ( x - pt1.x) + pt1.y。其垂线的斜率ؓ - 1 / kQ垂U方EؓQy = (-1/k) * (x - point.x) + point.y ?
联立两直U方E解得:x = ( k^2 * pt1.x + k * (point.y - pt1.y ) + point.x ) / ( k^2 + 1) Qy = k * ( x - pt1.x) + pt1.y;然后再判断垂x否在U段上,如果在线D上则返回垂I如果不在则计两端点到垂的距离Q选择距离垂较近的端点返回?
计算点到折线、矩形、多边Ş的最q点Q?/strong>
只要分别计算点到每条U段的最q点Q记录最q距,取其中最q距L的点即可?
计算点到圆的最q距d交点坐标Q?/strong>
如果该点在圆心,因ؓ圆心到圆周Q一点的距离相等Q返回UNDEFINED?
q接点P和圆心OQ如果POq于X_则根据P在O的左边还是右边计出最q点的横坐标为centerPoint.x - radius ?centerPoint.x + radius。如果POq于Y_则根据P在O的上边还是下边计出最q点的纵坐标?centerPoint.y -+radius?centerPoint.y - radius。如果PO不^行于X轴和Y_则PO的斜率存在且不ؓ0Q这时直UPO斜率为k = Q?P.y - O.y Q? ( P.x - O.x )。直UPO的方EؓQy = k * ( x - P.x) + P.y。设圆方Eؓ:(x - O.x ) ^2 + ( y - O.y ) ^2 = r ^2Q联立两方程l可以解出直UPO和圆的交点,取其中离P点较q的交点卛_?
计算两条q的线D늚交点Q?/strong>
对于两条q的线D,它们之间的位|关pL下图所C的几种情况。图(a)中两条线D|有交点;?(b) ?(d) 中两条线D|无穷焦点Q图 (c) 中两条线D|一个交炏V设line1是两条线D中较长的一条,line2是较短的一条,如果line1包含了line2的两个端点,则是?d)的情况,两线D|无穷交点Q如果line1只包含line2的一个端点,那么如果line1的某个端点等于被line1包含的line2的那个端点,则是?c)的情况,q时两线D只有一个交点,否则是?b)的情况,两线D也是有无穷的交点;如果line1不包含line2的Q何端点,则是?a)的情况,q时两线D|有交炏V?/p>
设一条线DؓL0 = P1P2Q另一条线D|直线为L1 = Q1Q2 Q要计算的就是L0和L1的交炏V?br>
1Q?首先判断L0和L1是否怺Q方法已在前文讨Q,如果不相交则没有交点Q否则说明L0和L1一定有交点Q下面就L0和L1都看作直U来考虑?
2Q?如果P1和P2横坐标相同,即L0q于Y?
a) 若L1也^行于Y_
i. 若P1的纵坐标和Q1的纵坐标相同Q说明L0和L1qQ假如L1是直U的话他们有无穷的交点,假如L1是线D늚话可?计算两条qU段的交?的算法求他们的交点(该方法在前文已讨Q;
ii. 否则说明L0和L1qQ他们没有交点;
b) 若L1不^行于Y_则交Ҏ坐标为P1的横坐标Q代入到L1的直U方E中可以计算Z点纵坐标Q?
3Q?如果P1和P2横坐标不同,但是Q1和Q2横坐标相同,即L1q于Y_则交Ҏ坐标为Q1的横坐标Q代入到L0的直U方E中可以计算Z点纵坐标Q?
4Q?如果P1和P2U坐标相同,即L0q于X?
a) 若L1也^行于X_
i. 若P1的横坐标和Q1的横坐标相同Q说明L0和L1qQ假如L1是直U的话他们有无穷的交点,假如L1是线D늚话可?计算两条qU段的交?的算法求他们的交点(该方法在前文已讨Q;
ii. 否则说明L0和L1qQ他们没有交点;
b) 若L1不^行于X_则交点纵坐标为P1的纵坐标Q代入到L1的直U方E中可以计算ZҎ坐标Q?
5Q?如果P1和P2U坐标不同,但是Q1和Q2U坐标相同,即L1q于X_则交点纵坐标为Q1的纵坐标Q代入到L0的直U方E中可以计算ZҎ坐标Q?
6Q?剩下的情况就是L1和L0的斜率均存在且不?的情?
a) 计算出L0的斜率K0QL1的斜率K1 Q?
b) 如果K1 = K2
i. 如果Q1在L0上,则说明L0和L1qQ假如L1是直U的话有无穷交点Q假如L1是线D늚话可?计算两条qU段的交?的算法求他们的交点(该方法在前文已讨Q;
ii. 如果Q1不在L0上,则说明L0和L1qQ他们没有交炏V?br>
c) 联立两直U的方程l可以解ZҎ
q个法q不复杂Q但是要分情况讨论清楚,其是当两条U段q的情况需要单独考虑Q所以在前文求两条qU段的算法单独写出来。另外,一开始就先利用矢量叉乘判断线D与U段Q或直线Q是否相交,如果l果是相交,那么在后面就可以线D全部看作直U来考虑。需要注意的是,我们可以直U或U段方程改写为ax+by+c=0的Ş式,q样一来上q过E的部分步骤可以合ƈQ羃短了代码长度Q但是由于先要求出参敎ͼq种法花Ҏ多的旉?
求线D|直线与折Uѝ矩形、多边Ş的交点:
分别求与每条边的交点卛_?
求线D|直线与圆的交?
讑֜心ؓOQ圆半径为rQ直U(或线D)L上的两点为P1,P2?
1. 如果L是线D且P1QP2都包含在圆O内,则没有交点;否则q行下一步?
2. 如果Lq于Y_
a) 计算圆心到L的距disQ?br> b) 如果dis > r 则L和圆没有交点Q?br> c) 利用勾股定理Q可以求Z交点坐标Q但要注意考虑L和圆的相切情c?br>
3. 如果Lq于X_做法与Lq于Y轴的情况cMQ?
4. 如果L既不qX轴也不^行Y_可以求出L的斜率KQ然后列出L的点斜式方程Q和圆方E联立即可求解出L和圆的两个交点;
5. 如果L是线D,对于2Q?Q?中求出的交点q要分别判断是否属于该线D늚范围内?
凸包的概念:
炚wQ的凸?convex hull)是指一个最凸多边形,满Q中的Ҏ者在多边形边上或者在其内。下图中q色线D表C的多边形就是点集Q={p0,p1,...p12}的凸包?/p>
现在已经证明了凸包算法的旉复杂度下界是O(n*logn),但是当凸包的点数h也被考虑q去的话QKrikpatrick和Seidel的剪枝搜索算法可以达到O(n*logh)Q在渐进意义下达到最优。最常用的凸包算法是Graham扫描法和Jarvis步进法。本文只单介l一下Graham扫描法,其正性的证明和Jarvis步进法的q程大家可以参考《算法导论》?
对于一个有三个或以上点的点集QQGraham扫描法的q程如下Q?
令p0为Q中Y-X坐标排序下最的?
?lt;p1,p2,...pm>为对其余Ҏ以p0Z心的极角逆时针排序所得的炚wQ如果有多个Ҏ相同的极角,除了距p0最q的点外全部U除
压p0q栈S
压p1q栈S
压p2q栈S
for i ← 3 to m
do while 由S的栈元素的下一个元素、S的栈元素以及pi构成的折U段不拐向左?br> 对SҎ
压piq栈S
return S;
此过E执行后Q栈S由底至顶的元素就是Q的凸包顶Ҏ逆时针排列的点序列。需要注意的是,我们对点按极角逆时针排序时Qƈ不需要真正求出极角,只需要求ZQ意两点的ơ序可以了。而这个步骤可以用前述的矢量叉U性质实现?
四、结?/strong>
管人类对几何学的研I从古代起便没有中断q,但是具体到借助计算机来解决几何问题的研IӞq只是停留在一个初U阶D,无论从应用领域还是发展前景来看,计算几何学都值得我们认真学习、加以运用,希望q篇文章能带你走q这个丰富多彩的世界?/p>
目前我知道的求逆序最快的适合ACM/ICPC的算法是归ƈ排序时计逆序个数Q时间复杂度是nlog2nQ而空间复杂度2n。JAVA模板Q服务器是校内的Q?/p>
归ƈ求逆序单原理:
归ƈ排序是分ȝ思想Q具体原理自己去看书吧。利用归q求逆序是指在对子序?s1和s2在归q时Q若s1[i]>s2[j]Q逆序状况Q,则逆序数加上s1.length-i,因ؓs1中i后面的数字对于s2[j]都是逆序的?/p>
TJU 2242:
直接上模板,记得m的奇偶要考虑的哦?/p>
PKU 1007:
求逆序敎ͼ然后排序输出p了?/p>
PKU 1804, PKU 2299:
是最单的关于逆序对的题目Q题目大意是l出一个序列,求最移动多步可能使它序Q规定只能相ȝ动?br>盔RUd的话Q假设a b 盔RQ若a<b 交换会增加逆序敎ͼ所以最好不要做此交换;若a==b 交换无意思,也不要进行此交换Qa>bӞ交换会减逆序Q序列更顺序,所以做交换?br>׃可知Q所谓的Ud只有一U情况,即a>bQ且一ơ移动的l果是逆序?。假讑ֈ始逆序是nQ每ơ移动减1Q那么就需要nơ移动时序列变ؓ序。所以题目{化ؓ直接求序列的逆序便可以了?/p>
ZJU 1481:
q题和本ơ预选赛的F略有怼Q不q要单得多。题意是l定序列sQ然后依ơ将序列首项U至序列,q样共有n-1ơ操作便回到了原序列Q操作类g循环左移Q。问qn-1ơ操作和原序列,他们的逆序数最的一ơ是多少Q?br>有模板在手,直观地可以想到是Q对于这nơ都求逆序敎ͼ然后输出最的一ơ就可以了,但这样做的复杂度有O(n*nlogn),太过复杂?br>如果只求初始序列的逆序数的话,只要后面的n-1ơ操作的逆序数能够在O(1)的算法下求得Q就能保证MO(nlogn)的复杂度了。事实上Q对于每ơ操作确实可以用O(1)的算法求得逆序数。将序列中aiUdaj的后面,是ai做j-iơ与右邻的交换,而每ơ交换有三个l果Q逆序+1、逆序-1、逆序不变。由于题目中说明序列中无相同,所以逆序不变可以忽略。逆序的加减是看ai与aj_包括ajQ的数字大小关系Q所以求出ai与aj间大于ai的数字个数和于ai的数字个数然后取差,是aiUd到aj后面所D的逆序值变化了?br>依据上面的道理,因ؓ题目有要求ai是移动到最后一个数Q而ai又必定是头项Q所以只要计大于ai的个数和于ai的个C差就行了。然后每ơ对于前一ơ的逆序数加上这个差Q就是经q这ơ操作后的逆序数g?/p>
PKU 2086:
q题不是求逆序对,而是知道逆序数k来制造一个序列。要求序列最,两个序列比较大小是自左向右依ơ比较项Q拥有较大项的序列大?
其实造序列ƈ不难Q由1804可知Q只要对盔R数做调整p做到某个逆序C。难Ҏ在求最的序列。D?1 2 3 4 5,要求逆序1的最序列是交换4 5Q如果交换其他Q意相L都无法保证最。由此可以想刎ͼ要保证序列最,前部分序列可以不动(因ؓ他们已经是最的了)Q只改动后半部分。而我们知道n个数的最大逆序数是n*(n-1)/2Q所以可以求一个最的pQ?k<p*(p-1)/2。得到前半部分是1到n-pQ所有的逆序都是由后半部分p个数完成的?br>考虑k=7,n=6的情况,求得p=5,卛_部分1不动Q后?个数字调整?个数的最大逆序? 4 3 2,逆序数是6Q?个数? 5 4 3 2,逆序数是10。可以猜惛_Q保??个数的逆序不动Q调整另一个数的位|就可以增加或减逆序敎ͼq样p调整?-10间的L逆序。ؓ了保证最,我们可以取尽量小的数前移到最左的位置p了?前移后逆序调整4Q?前移后调整了3Q?调整2Q?调整1Q不动是调整0Q可以通过q样调整得到?-10Q所以规律就是找到需要调整的敎ͼ剩下的部分就逆序输出。需要调整的数可以通过总逆序k-(p-1)*(p-2)/2+(n-p)求得?/p>
PKU 1455:
q是一道比较难的关于逆序数推理的题目Q题目要求是n人组成一个环Q求做相M换的操作最多次可以使每个h左右的邻居互换,卛_先左边的到右边去Q原双的去左边。容易想到的是给n个h~号Q从1..nQ那么初始态是1..n然后n双?Q目标态是n..1Qn左边??br>初步看上d象结果就是求下逆序Qn*(n-1)/2 ?Q,但是隄是此题的序列是一个环。在环的情况下,可以减少许多ơ移动。先从非环的情况思考,?-n的序列要转化成n-1的序列,是做n(n-1)/2ơ操作。因为是环,所?k)..1,n..k+1也可以算是目标态。例如:1 2 3 4 5 6的目标可以是 6 5 4 3 2 1,也可以是 4 3 2 1 6 5。所以,问题可以转化为求形如(k)..1,n..k+1的目标态中k取何值时Q逆序数最?br>l过上面的步骤,问题已经和ZJU1481cM的。但其实Q还是有规律可@的。对于某kQ他的逆序数是左边的逆序?双的逆序敎ͼ也就?k*(k-1)/2)+((n-k)*(n-k-1)/2) Qk>=1 && k<=nQ。展开一下,可以求得k{于n/2旉序数最ؓ((n*n-n)/2)Q现在把k代入q去可以得到解了?br>要注意的是k是整敎ͼn/2不一定是整数Q所以公式还有修改的余地Q可以通用地改?n/2)*(n-1)/2?/p>
PKU 2893:
用到了求逆序数的思想Q但针对题目q有优化Q可见M*N PUZZLE的优化?/p>
PKU 1077:
比较l典的搜索题Q但在判断无解的情况下,逆序数帮了大忙,可见八数码实验报告?/p>
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/ray58750034/archive/2006/10/08/1325939.aspx
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/ray58750034/archive/2006/10/08/1325939.aspx
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/ray58750034/archive/2006/10/08/1325939.aspx
一般采取树形结构来存储q查集,在合q操作时可以利用树的节点?加权规则)或者利用一个rank数组来存储集合的深度下界--启发式函敎ͼ在查找操作时q行路径压羃使后l的查找操作加速?/font>q样优化实现的ƈ查集Q空间复杂度为O(N)Q徏立一个集合的旉复杂度ؓO(1)QNơ合qM查找的时间复杂度为O(M Alpha(N))Q这里Alpha是Ackerman函数的某个反函数Q在很大的范围内q个函数的值可以看成是不大?的,所以ƈ查集的操作可以看作是U性的?br>它支持以下三U操? 以下l出我的两种实现: POJ 1611 The Suspects 最基础的ƈ查集 JOJ 1905 Freckles == POJ 2560 最生成树 法一QPrim法Q法二:q查集实?font color=#000000>Kruskar法求最生成树
QUnion (Root1, Root2) //合ƈ操作Q把子集合Root2和子集合Root1合ƈ.要求QRoot1?Root2互不怺,否则不执行操?
QFind (x) //搜烦操作Q搜索元素x所在的集合,q返回该集合的名?-根节?
QUFSets (s) //构造函数。将q查集中s个元素初始化为s个只有一个单元素的子集合.
Q对于ƈ查集来说Q每个集合用一|表示?br> Q集合中每个元素的元素名分别存放在树的结点中Q此外,树的每一个结点还有一个指向其双亲l点的指针?nbsp;
Qؓ化讨论,忽略实际的集合名Q仅用表C集合的树的Ҏ标识集合?/p>
//Abstract: UFSet
2
3//Author:Lifeng Wang QFandywangQ?br> 4
5
6
7
8// Model One 与Model 2 路径压羃方式不同,合ƈ标准不同
9
10const int MAXSIZE = 500010;
11
12int rank[MAXSIZE]; // 节点高度的上?/span>
13
14int parent[MAXSIZE]; // 根节?/span>
15
16int FindSet(int x)
{// 查找+递归的\径压~?/span>
17
18 if( x != parent[x] ) parent[x] = FindSet(parent[x]);
19
20 return parent[x];
21
22}
23
24void Union(int root1, int root2)
{
25
26 int x = FindSet(root1), y = FindSet(root2);
27
28 if( x == y ) return ;
29
30 if( rank[x] > rank[y] ) parent[y] = x;
31
32 else
{
33
34 parent[x] = y;
35
36 if( rank[x] == rank[y] ) ++rank[y];
37
38 }
39
40}
41
42void Initi(void)
{
43
44 memset(rank, 0, sizeof(rank));
45
46 for( int i=0; i < MAXSIZE; ++i ) parent[i] = i;
47
48}
49
50
51
52
53// Model Two
54
55const int MAXSIZE = 30001;
56
57int pre[MAXSIZE]; //根节点i,pre[i] = -num,其中num是该树的节点数目;
58
59 //非根节点j,pre[j] = k,其中k是j的父节点
60
61int Find(int x)
{//查找+非递归的\径压~?/span>
62
63 int p = x;
64
65 while( pre[p] > 0 ) p = pre[p];
66
67 while( x != p )
{
68
69 int temp = pre[x]; pre[x] = p; x = temp;
70
71 }
72
73 return x;
74
75}
76
77void Union(int r1, int r2)
{
78
79 int a = Find(r1); int b = Find(r2);
80
81 if( a == b ) return ;
82
83 //加权规则合ƈ
84
85 if( pre[a] < pre[b] )
{
86
87 pre[a] += pre[b]; pre[b] = a;
88
89 }
90
91 else
{
92
93 pre[b] += pre[a]; pre[a] = b;
94
95 }
96
97}
98
99void Initi(void)
100
101{
102
103 for( int i=0; i < N; ++i ) pre[i] = -1;
104
105}
106
107
q查集的一些题目和我的相关解题报告:
POJ 2524 Ubiquitous Religions 最基本的ƈ查集
POJ 1182 食物?/u> q查集的拓展
注意: 只有一l数?
要充分利用题意所l条?有三cd物A,B,CQ这三类动物的食物链
构成了有的环Ş。A吃BQ?B吃CQC吃A。也是?只有三个group
POJ 2492 A Bug's Life q查集的拓展
法一:深度优先遍历
每次遍历记录下该Ҏ甯是女Q只??〉女Q女-〉男满Q否则,扑ֈ同性恋Q结束程序?br>法二:二分囑?br>法三:q查集的拓展:?182很像Q只不过q里有两组Q?182是三l?1611无限?br>POJ 1861 Network == zju_1542 q查?自定义排?贪心?最生成树"
{案不唯一Q不q在ZOJ上用QSORT()和SORT()都能q,在POJ上只有SORT()才能q?..
POJ 1703 Find them, Catch them q查集的拓展
q个?/font>POJ 2492 A Bug's Life很像Q就是把代码E微修改了一下就AC了!
注意QAnd of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. 是说只有两个组?br>POJ 2236 Wireless Network q查集的应用
需要注意的地方Q?、ƈ查集Q?、N的范_可以{于1001Q?、从N+1行开始,W一个输入的可以是字W串?br>POJ 1988 Cube Stacking q查集很好的应用
1、与 银河英雄传说==NOI2002 Galaxy一P2、增加了一个数lbehind[x],记录战舰x在列中的相对位置Q?、详l解题报告见银河英雄传说?/font>
JOJ 1966 Super Market III == PKU 1456 Supermarket 带限制的作业排序问题Q贪?q查集)
提高题目Q?br>POJ 2912 Rochambeau
POJ 1733 Parity game
POJ 1308 Is It A Tree?
上次在湖大,其中的一道题数据很强Q我试了好多U优化都TLEQ相信只能用U段树才能过。回来之后暗暗又学了一ơ线D|Q想惛_像是W三ơ学了,像网l流一h学一ơ都有新的体会?/p>
把问题简化一下:
在自然数Q且所有的C大于30000的范围内讨论一个问题:现在已知n条线D,把端点依ơ输入告诉你Q然后有m个询问,每个询问输入一个点Q要求这个点在多条U段上出现过Q?/p>
最基本的解法当然就是读一个点Q就把所有线D|一下,看看在不在线D中Q?/p>
每次询问都要把n条线D|一ơ,那么mơ询问,pq算m*nơ,复杂度就是O(m*n)
q道题m和n都是30000Q那么计量辑ֈ?0^9Q而计机1U的计算量大U是10^8的数量Q所以这U方法无论怎么优化都是时
-----
因ؓn条线D|固定的,所以某U程度上说每ơ都把n条线D|一遍有大量的重复和费Q?/p>
U段树就是可以解册c问题的数据l构
举例说明Q已知线D[2,5] [4,6] [0,7]Q求?,4,7分别出现了多次
在[0,7]区间上徏立一|二叉树:Qؓ了和已知U段区别Q用【】表C线D|中的U段Q?/p>
?,7?/p>
/ \
?,3?nbsp; ?,7?/p>
/ \ / \
?,1?nbsp; ?,3?nbsp; ?,5?nbsp; ?,7?/p>
/ \ / \ / \ / \
?,0??,1】?,2??,3?nbsp; ?,4??,5??,6??,7?/p>
每个节点用结构体Q?/p>
struct line
{
int left,right;//左端炏V右端点
int n;//记录q条U段出现了多次Q默认ؓ0
}a[16];
和堆cMQ满二叉树的性质军_a[i]的左儿子是a[2*i]、右儿子是a[2*i+1];
然后对于已知的线D依ơ进行插入操作:
从树根开始调用递归函数insert
三条已知U段插入q程Q?/p>
[2,5]
--[2,5]与?,7】比较,分成两部分:[2,3]插到左儿子?,3】,[4,5]插到叛_子?,7?/p>
--[2,3]与?,3】比较,插到叛_子?,3】;[4,5]和?,7】比较,插到左儿子?,5?/p>
--[2,3]与?,3】匹配,?,3】记?1Q[4,5]与?,5】匹配,?,5】记?1
[4,6]
--[4,6]与?,7】比较,插到叛_子?,7?/p>
--[4,6]与?,7】比较,分成两部分,[4,5]插到左儿子?,5】;[6,6]插到叛_子?,7?/p>
--[4,5]与?,5】匹配,?,5】记?1Q[6,6]与?,7】比较,插到左儿子?,6?/p>
--[6,6]与?,6】匹配,?,6】记?1
[0,7]
--[0,7]与?,7】匹配,?,7】记?1
插入q程l束Q线D|上的记录如下Q红色数字ؓ每条U段的记录nQ:
?,7?/p>
1
/ \
?,3?nbsp; ?,7?/p>
0 0
/ \ / \
?,1?nbsp; ?,3?nbsp; ?,5?nbsp; ?,7?/p>
0 1 2 0
/ \ / \ / \ / \
?,0??,1??,2??,3??,4??,5??,6??,7?/p>
0 0 0 0 0 0 1 0
询问操作和插入操作类|也是递归q程Q略
2——依ơ把?,7??,3??,3??,2】的记录n加v来,l果?
4——依ơ把?,7??,7??,5??,4】的记录n加v来,l果?
7——依ơ把?,7??,7??,7??,7】的记录n加v来,l果?
不管是插入操作还是查询操作,每次操作的执行次C为树的深度——logN
建树有nơ插入操作,n*logNQ一ơ查询要logNQmơ就是m*logNQd复杂度O(n+m)*logNQ这道题N不超q?0000QlogNU等?4Q所以计量?0^5?0^6之间Q比普通方法快?000倍;
q道题是U段树最基本的操作,只用C插入和查找;删除操作和插入类|扩展功能的还有测度、连l段数等{,在N数据范围很大的时候,依然可以用离散化的方法徏树?/p>
湖大的那道题目绕了个弯子,alpc12有详l的题目和解题报告,有兴的话可以看?a href="http://m.shnenglu.com/sicheng/archive/2008/01/09/40791.html">http://m.shnenglu.com/sicheng/archive/2008/01/09/40791.html
U段树的l典题目是poj1177的picturehttp://acm.pku.edu.cn/JudgeOnline/problem?id=1177
Bellman-Ford法与另一个非常著名的Dijkstra法一P用于求解单源Ҏ短\径问题?/span>Bellman-ford法除了可求解边权均非负的问题外Q还可以解决存在负权边的问题Q意义是什么,好好思考)Q?/span>Dijkstra法只能处理Ҏ非负的问题,因此 Bellman-Ford法的适用面要q泛一些。但是,原始?/span>Bellman-Ford法旉复杂度ؓ OQ?/span>VEQ?/span>,?/span>Dijkstra法的时间复杂度高,所以常常被众多的大学算法教U书所忽略Q就q经典的《算法导论》也只介l了基本?/span>Bellman-Ford法Q在国内常见的基本信息学奥赛教材中也均未提及Q因此该法的知名度与被掌握度都不如Dijkstra法。事实上Q有多种形式?/span>Bellman-Ford法的优化实现。这些优化实现在旉效率上得到相当提升,例如q一两年被热捧的SPFAQ?/span>Shortest-Path Faster Algoithm 更快的最短\径算法)法的时间效率甚至由?/span>Dijkstra法Q因此成Z息学奥赛选手l常讨论的话题。然而,限于资料匮乏Q有?/span>Bellman-Ford法的诸多问题常常困扰奥赛选手。如Q该法值得掌握么?怎样用编E语a具体实现Q有哪些优化Q与SPFA法有关pMQ本文试囑֯Bellman-Ford法做一个比较全面的介绍。给出几U实现程序,从理论和实测两方面分析他们的旉复杂度,供大家在备战省选和后箋?/span>noi时参考?/span>
Bellman-Ford法能在更普遍的情况下(存在负权边)解决单源Ҏ短\径问题。对于给定的带权Q有向或无向Q图 G=Q?/span>V,EQ,其源点ؓsQ加权函?/span> w?/span> 辚w E 的映。对?/span>Gq行Bellman-Ford法的结果是一个布|表明图中是否存在着一个从源点s可达的负权回路?/span>若不存在q样的回路,法给Z源点s?/span> ?/span>G的Q意顶?/span>v的最短\?/span>d[v]?/span>
Q?Q?span> 初始化:除源点外的所有顶点的最短距M计?/span> d[v] ←+∞, d[s] ←0;
Q?Q?span> q代求解Q反复对辚wE中的每条边进行松弛操作,使得点集V中的每个点v的最短距M计值逐步D其最短距;Q运行|v|-1ơ)
Q?Q?span> 验负权回路:判断辚wE中的每一条边的两个端Ҏ否收敛。如果存在未收敛的顶点,则算法返?/span>falseQ表明问题无解;否则法q回trueQƈ且从源点可达的顶?/span>v的最短距M存在 d[v]中?/span>
法描述如下Q?/span>
Bellman-Ford(G,w,s) Q?/span>boolean //?/span>G Q边?/span> 函数 w Q?/span>s为源?/span>
1 for each vertex v ∈ VQGQ?do //初始?span> 1阶段
2 d[v] ←+∞
3 d[s] ←0; //1阶段l束
4 for i=1 to |v|-1 do //2阶段开始,双重循环?/span>
5 for each edgeQu,vQ?∈E(G) do //辚w数组要用刎ͼID每条辏V?/span>
6 If d[v]> d[u]+ w(u,v) then //村ּ判断
7 d[v]=d[u]+w(u,v) //村ּ操作 2阶段l束
8 for each edgeQu,vQ?∈E(G) do
9 If d[v]> d[u]+ w(u,v) then
10 Exit false
11 Exit true
下面l出描述性证明:
首先指出Q图的Q意一条最短\径既不能包含负权回\Q也不会包含正权回\Q因此它最多包?/span>|v|-1条边?/span>
其次Q从源点s可达的所有顶点如?/span> 存在最短\径,则这些最短\径构成一个以s为根的最短\径树?/span>Bellman-Ford法的P代松弛操作,实际上就是按点距离s的层ơ,逐层生成q棵最短\径树的过E?/span>
在对每条边进?span>1遍松弛的时候,生成了从s出发Q层ơ至多ؓ1的那些树枝。也是_扑ֈ了与s臛_?条边相联的那些顶点的最短\径;Ҏ条边q行W?遍松弛的时候,生成了第2层次的树枝,是说找Cl过2条边相连的那些顶点的最短\?#8230;…。因为最短\径最多只包含|v|-1 条边Q所以,只需要@环|v|-1 ơ?/span>
每实施一ơ松弛操作,最短\径树上就会有一层顶点达到其最短距,此后q层点的最短距d就会一直保持不变,不再受后l松弛操作的影响。(但是Q每ơ还要判断松弛,q里费了大量的旉Q怎么优化Q单U的优化是否可行Q)
如果没有负权回\Q由于最短\径树的高度最多只能是|v|-1Q所以最多经q|v|-1遍松弛操作后Q所有从s可达的顶点必求出最短距R如?d[v]仍保?+∞Q则表明从s到v不可达?/span>
如果有负权回路,那么W?span> |v|-1 遍松弛操作仍然会成功Q这Ӟ负权回\上的点不会收敛?/span>
例如对于上图Q边上方框中的数字代表权|点A,B,C之间存在负权回\。S是源点,点中数字表C行Bellman-Ford法后各点的最短距M计倹{?/span>
此时d[a]的gؓ1Q大于d[c]+w(c,a)的?2Q由此d[a]可以村ּ?2Q然后d[b]又可以松弛ؓ-5,d[c]又可以松弛ؓ-7.下一个周期,d[a]又可以更Cؓ更小的|q个q程永远不会l止。因此,在P代求解最短\径阶D늻束后Q可以通过验边集E的每条边(u,v)是否满关系?span> d[v]> d[u]+ w(u,v) 来判断是否存在负权回路?/span>