??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久久久久综合日本,看全色黄大色大片免费久久久 ,中文成人无码精品久久久不卡http://m.shnenglu.com/proyao/category/10226.html基础不牢Q地动山?.. 急不?..zh-cnFri, 13 Aug 2010 01:02:39 GMTFri, 13 Aug 2010 01:02:39 GMT60Pick定理Q很牛的定理Q?[转]http://m.shnenglu.com/proyao/archive/2009/10/06/97960.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiTue, 06 Oct 2009 09:59:00 GMThttp://m.shnenglu.com/proyao/archive/2009/10/06/97960.htmlhttp://m.shnenglu.com/proyao/comments/97960.htmlhttp://m.shnenglu.com/proyao/archive/2009/10/06/97960.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/97960.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/97960.htmll定点座标均是整点Q或正方?/font>格点Q的?a title=多邊?>多边?/font>Q?strong>皮克定理说明了其面积A和内部格Ҏ?em>i、边上格Ҏ?em>b的关p:A = i + b/2 - 1?

证明

因ؓ所有简单多边Ş都可切割Z?a title=三角?>三角?/font>和另一个简单多边Ş。考虑一个简单多边ŞPQ及?em>P有一条共同边的三角ŞT。若PW合皮克公式Q则只要证明P加上T?em>PT亦符合皮克公式(IQ,与及三角形符合皮克公式(IIQ,可Ҏ数学归纳?/font>Q对于所有简单多边Ş皮克公式都是成立的?

多边?/h3>

?em>P?em>T的共同边上有c个格炏V?

  • P的面U: iP + bP/2 - 1
  • T的面U: iT + bT/2 - 1
  • PT的面U:
(iT + iP + c - 2) + (bT- c + 2 + bP - c + 2 ) /2 - 1
= iPT + bPT/2 - 1

三角?/h3>

证明分三部分Q证明以下的囑ŞW合皮克定理Q?

  1. 所有^行于轴线的矩形;
  2. 以上q矩形的两条邻边和对角线l成的直角三角ŞQ?
  3. 所有三角ŞQ因为它们都可内接于矩Ş内,矩形分割成原三角Ş和至?个第二点提到的直角三角ŞQ?

矩Ş

讄?em>R长边短边各有m,n个格点:

  • AR = (m-1)(n-1)
  • iR = (m-2)(n-2)
  • bR = 2(m+n)-4
iR + bR/2 - 1
= (m-2)(n-2) + (m+n) - 2 - 1
= mn - (m + n) +1
= (m-1)(n-1)

直角三角?/h4>

易见两条邻边?a title=角R?>对角U?/font>l成的两个直角三角Ş全等Q且i,b相等。设其斜边上?em>c个格炏V?

  • b = m+n+c-3
  • i = ((m-2)(n-2) - c + 2)/2
i + b/2 - 1
= ((m-2)(n-2) - c + 2)/2 + (m+n+c-3)/2 - 1
= (m-2)(n-2)/2 + (m+n - 3)/2
= (m-1)(n-1)/2

一般三角Ş

推广

  • 取格点的l成囑Ş的面Uؓ一单位。在q四边?/font>格点Q皮克定理依然成立。套用于L三角形格点,皮克定理则是A = 2i + b - 2?
  • 对于非简单的多边?em>PQ皮克定?em>A = i + b/2 - χ(P)Q其?#967;(P)表示P?a title=Ƨ拉特征?>Ƨ拉特征?/font>?
  • 高维推广Q?a class=new title=Ehrhart多項?>Ehrhart多项?/font>Q一l_植树问题?
  • 皮克定理和欧拉公式(V-E+F=2Q等仗?

定理提出?/h2>

Georg Alexander PickQ?a title=1859q?>1859q?/font>生于l也U?/font>Q?a title=1943q?>1943q?/font>M特莱西恩施塔牚w中营?

相关书籍

外部q结

en:Pick's theorem fr:Théorème de Pick it:Teorema di Pick pl:Wzór Picka ru:Теорема Пиaа



]]>计算几何常用法概览http://m.shnenglu.com/proyao/archive/2009/10/06/97940.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiTue, 06 Oct 2009 06:38:00 GMThttp://m.shnenglu.com/proyao/archive/2009/10/06/97940.htmlhttp://m.shnenglu.com/proyao/comments/97940.htmlhttp://m.shnenglu.com/proyao/archive/2009/10/06/97940.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/97940.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/97940.html一、引a

计算机的出现使得很多原本十分J琐的工作得以大q度化,但是也有一些在Z直观看来很容易的问题却需要拿Z套ƈ不简单的通用解决ҎQ比如几何问题。作机U学的一个分支,计算几何主要研究解决几何问题的算法。在C工程和数学领域,计算几何在图形学、机器h技术、超大规模集成电路设计和l计{诸多领域有着十分重要的应用。在本文中,我们对计算几何常用的基本算法做一个全面的介绍Q希望对您了解ƈ应用计算几何的知识解决问题v到帮助?br>
二、目?/strong>

  本文整理的计几何基本概念和常用法包括如下内容Q?br>
  矢量的概?br>
  矢量加减?br>
  矢量叉积

  折线D늚拐向判断

  判断Ҏ否在U段?br>
  判断两线D|否相?br>
  判断U段和直U是否相?br>
  判断矩Ş是否包含?br>
  判断U段、折Uѝ多边Ş是否在矩形中

  判断矩Ş是否在矩形中

  判断圆是否在矩Ş?br>
  判断Ҏ否在多边形中

  判断U段是否在多边Ş?br>
  判断折线是否在多边Ş?br>
  判断多边形是否在多边形内

  判断矩Ş是否在多边Ş?br>
  判断圆是否在多边形内

  判断Ҏ否在圆内

  判断U段、折Uѝ矩形、多边Ş是否在圆?br>
  判断圆是否在圆内

  计算点到U段的最q点

  计算点到折线、矩形、多边Ş的最q点

  计算点到圆的最q距d交点坐标

  计算两条q的线D늚交点

  计算U段或直U与U段的交?br>
  求线D|直线与折Uѝ矩形、多边Ş的交?br>
  求线D|直线与圆的交?br>
  凸包的概?br>
  凸包的求?br>
三、算法介l?/strong>

矢量的概念:

如果一条线D늚端点是有ơ序之分的,我们把这U线D|为有向线D?directed segment)。如果有向线Dp1p2的v点p1在坐标原点,我们可以把它UCؓ矢量(vector)p2?br>
矢量叉积Q?/strong>

计算矢量叉积是与直线和线D늛关算法的核心部分。设矢量P = Qx1,y1Q?QQ = (x2,y2)Q则矢量叉积定义为由(0,0)、p1、p2和p1+p2所l成的^行四边Ş的带W号的面U,卻IP × Q = x1*y2 - x2*y1Q其l果是一个标量。显然有性质 P × Q = - ( Q × P ) ?P × ( - Q ) = - ( P × Q )。一般在不加说明的情况下Q本文下q算法中所有的炚w看作矢量Q两点的加减法就是矢量相加减Q而点的乘法则看作矢量叉积?br>
  叉积的一个非帔R要性质是可以通过它的W号判断两矢量相互之间的逆时针关p:

  ?P × Q > 0 , 则P在Q的顺旉方向?br>  ?P × Q < 0 , 则P在Q的逆时针方向?br>  ?P × Q = 0 , 则P与QqQ但可能同向也可能反向?br>
折线D늚拐向判断Q?/strong>

  折线D늚拐向判断Ҏ可以直接q量叉U的性质推出。对于有公共端点的线Dp0p1和p1p2Q通过计算(p2 - p0) × (p1 - p0)的符号便可以定折线D늚拐向Q?br>
  ?p2 - p0) × (p1 - p0) > 0,则p0p1在p1Ҏ向右侧后得到p1p2?br>
  ?p2 - p0) × (p1 - p0) < 0,则p0p1在p1Ҏ向左侧后得到p1p2?br>
  ?p2 - p0) × (p1 - p0) = 0,则p0、p1、p2三点q?br>
  具体情况可参照下图:

判断Ҏ否在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>
判断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>

Zl一赯Q我们在计算线L和多边Ş的交点的时候,1。对于多边Ş的水q不作考虑Q?。对于多边Ş的顶点和L怺的情况,如果该顶Ҏ其所属的边上U坐标较大的点Q则计数Q否则忽略;3。对于P在多边Ş边上的情形,直接可判断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>

因此我们可以先求出所有和U段怺的多边Ş的顶点,然后按照X-Y坐标排序(X坐标的排在前面Q对于X坐标相同的点QY坐标的排在前面Q这U排序准则也是ؓ了保证水q_垂直情况的判断正?Q这Lȝ两个点就是在U段上相ȝ两交点,如果L盔R两点的中点也在多边Ş内,则该U段一定在多边形内?

  证明如下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>

 

计算U段或直U与U段的交?

  设一条线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>



]]>
计算几何常用法概览http://m.shnenglu.com/proyao/archive/2009/10/06/97941.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiTue, 06 Oct 2009 06:38:00 GMThttp://m.shnenglu.com/proyao/archive/2009/10/06/97941.htmlhttp://m.shnenglu.com/proyao/comments/97941.htmlhttp://m.shnenglu.com/proyao/archive/2009/10/06/97941.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/97941.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/97941.html一、引a

计算机的出现使得很多原本十分J琐的工作得以大q度化,但是也有一些在Z直观看来很容易的问题却需要拿Z套ƈ不简单的通用解决ҎQ比如几何问题。作机U学的一个分支,计算几何主要研究解决几何问题的算法。在C工程和数学领域,计算几何在图形学、机器h技术、超大规模集成电路设计和l计{诸多领域有着十分重要的应用。在本文中,我们对计算几何常用的基本算法做一个全面的介绍Q希望对您了解ƈ应用计算几何的知识解决问题v到帮助?br>
二、目?/strong>

  本文整理的计几何基本概念和常用法包括如下内容Q?br>
  矢量的概?br>
  矢量加减?br>
  矢量叉积

  折线D늚拐向判断

  判断Ҏ否在U段?br>
  判断两线D|否相?br>
  判断U段和直U是否相?br>
  判断矩Ş是否包含?br>
  判断U段、折Uѝ多边Ş是否在矩形中

  判断矩Ş是否在矩形中

  判断圆是否在矩Ş?br>
  判断Ҏ否在多边形中

  判断U段是否在多边Ş?br>
  判断折线是否在多边Ş?br>
  判断多边形是否在多边形内

  判断矩Ş是否在多边Ş?br>
  判断圆是否在多边形内

  判断Ҏ否在圆内

  判断U段、折Uѝ矩形、多边Ş是否在圆?br>
  判断圆是否在圆内

  计算点到U段的最q点

  计算点到折线、矩形、多边Ş的最q点

  计算点到圆的最q距d交点坐标

  计算两条q的线D늚交点

  计算U段或直U与U段的交?br>
  求线D|直线与折Uѝ矩形、多边Ş的交?br>
  求线D|直线与圆的交?br>
  凸包的概?br>
  凸包的求?br>
三、算法介l?/strong>

矢量的概念:

如果一条线D늚端点是有ơ序之分的,我们把这U线D|为有向线D?directed segment)。如果有向线Dp1p2的v点p1在坐标原点,我们可以把它UCؓ矢量(vector)p2?br>
矢量叉积Q?/strong>

计算矢量叉积是与直线和线D늛关算法的核心部分。设矢量P = Qx1,y1Q?QQ = (x2,y2)Q则矢量叉积定义为由(0,0)、p1、p2和p1+p2所l成的^行四边Ş的带W号的面U,卻IP × Q = x1*y2 - x2*y1Q其l果是一个标量。显然有性质 P × Q = - ( Q × P ) ?P × ( - Q ) = - ( P × Q )。一般在不加说明的情况下Q本文下q算法中所有的炚w看作矢量Q两点的加减法就是矢量相加减Q而点的乘法则看作矢量叉积?br>
  叉积的一个非帔R要性质是可以通过它的W号判断两矢量相互之间的逆时针关p:

  ?P × Q > 0 , 则P在Q的顺旉方向?br>  ?P × Q < 0 , 则P在Q的逆时针方向?br>  ?P × Q = 0 , 则P与QqQ但可能同向也可能反向?br>
折线D늚拐向判断Q?/strong>

  折线D늚拐向判断Ҏ可以直接q量叉U的性质推出。对于有公共端点的线Dp0p1和p1p2Q通过计算(p2 - p0) × (p1 - p0)的符号便可以定折线D늚拐向Q?br>
  ?p2 - p0) × (p1 - p0) > 0,则p0p1在p1Ҏ向右侧后得到p1p2?br>
  ?p2 - p0) × (p1 - p0) < 0,则p0p1在p1Ҏ向左侧后得到p1p2?br>
  ?p2 - p0) × (p1 - p0) = 0,则p0、p1、p2三点q?br>
  具体情况可参照下图:

判断Ҏ否在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>
判断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>

Zl一赯Q我们在计算线L和多边Ş的交点的时候,1。对于多边Ş的水q不作考虑Q?。对于多边Ş的顶点和L怺的情况,如果该顶Ҏ其所属的边上U坐标较大的点Q则计数Q否则忽略;3。对于P在多边Ş边上的情形,直接可判断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>

因此我们可以先求出所有和U段怺的多边Ş的顶点,然后按照X-Y坐标排序(X坐标的排在前面Q对于X坐标相同的点QY坐标的排在前面Q这U排序准则也是ؓ了保证水q_垂直情况的判断正?Q这Lȝ两个点就是在U段上相ȝ两交点,如果L盔R两点的中点也在多边Ş内,则该U段一定在多边形内?

  证明如下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>

 

计算U段或直U与U段的交?

  设一条线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>



]]>
关于“逆序数”[转]http://m.shnenglu.com/proyao/archive/2009/07/12/89863.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiSun, 12 Jul 2009 06:57:00 GMThttp://m.shnenglu.com/proyao/archive/2009/07/12/89863.htmlhttp://m.shnenglu.com/proyao/comments/89863.htmlhttp://m.shnenglu.com/proyao/archive/2009/07/12/89863.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/89863.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/89863.html昨天我们做了清华的预选赛Q沈大、梁老大、肖叉各搞定一道题Q险些跌?0名。我做了B和FQ其中F是关于逆序数的题目Q复杂度?nlog2n+mn 最差的复杂度可能降为O(n^2)。但我提交的l果不是TLEQ而是MLE和RE。真不知道是清华判题pȝ有问题还是我的程序有问题。MQ我心有不服啊,所以决定今天花Ҏ间归U一?#8220;逆序?#8221;的题目,l大家写份报告,提供点资料?首先Q逆序对(inversion pairQ是指在序列{a0,a1,a2...an}中,若ai<aj(i>j)Q则(ai,aj)上一寚w序寏V而逆序敎ͼinversion numberQ顾名思义是序列中逆序对的个数。例如: 1 2 3是顺序,则逆序数是0Q? 3 2?2,3)满逆序对的条gQ所以逆序数只?Q?3 2 1?1,2)(1,3)(2,3)满逆序对,所以逆序?。由定义不能惌Q序列n的逆序数范围在[0,n*(n-1)/2]Q其中顺序时逆序Cؓ0Q完全逆序旉序数是n*(n-1)/2?/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查集及其应用[转]http://m.shnenglu.com/proyao/archive/2009/04/21/80611.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiTue, 21 Apr 2009 06:56:00 GMThttp://m.shnenglu.com/proyao/archive/2009/04/21/80611.htmlhttp://m.shnenglu.com/proyao/comments/80611.htmlhttp://m.shnenglu.com/proyao/archive/2009/04/21/80611.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/80611.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/80611.htmlhttp://hi.baidu.com/fandywang_jlu/blog/item/b49e40893ddbb0b00f244485.html
q查集:(union-find sets)是一U简单的用途广泛的集合. q查集是若干个不怺集合Q能够实现较快的合ƈ和判断元素所在集合的操作Q应用很多,如其求无向图的连通分量个数、最公q先、带限制的作业排序,q有最完美的应用:实现Kruskar法求最生成树。其实,q一部分《算法导论》讲的很_?

       一般采取树形结构来存储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操?
  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>

以下l出我的两种实现:

  1//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, 0sizeof(rank));
 45
 46     forint 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    forint i=0; i < N; ++i ) pre[i] = -1;
104
105}
          
106
107

q查集的一些题目和我的相关解题报告:

 

POJ 1611 The Suspects          最基础的ƈ查集
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 1905 Freckles   == POJ 2560 最生成树

法一QPrim法Q法二:q查集实?font color=#000000>Kruskar法求最生成树

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?



]]>
RMQhttp://m.shnenglu.com/proyao/archive/2009/04/14/79842.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiMon, 13 Apr 2009 16:40:00 GMThttp://m.shnenglu.com/proyao/archive/2009/04/14/79842.htmlhttp://m.shnenglu.com/proyao/comments/79842.htmlhttp://m.shnenglu.com/proyao/archive/2009/04/14/79842.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/79842.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/79842.html<O(N logN), O(1)>
 1void rmq_init()
 2{
 3    int i,j;
 4    for(j=1;j<=n;j++) mx[j][0]=d[j];
 5    int m=floor(log((double)n)/log(2.0));
 6    for(i=1;i<=m;i++)
 7        for(j=0;j+(1<<(i-1))<=n;j++)
 8            mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);
 9}

10
11int rmq(int l,int r)
12{
13    int m=floor(log((double)(r-l+1))/log(2.0));
14    int a=max(mx[l][m],mx[r-(1<<m)+1][m]);
15    return a;  
16}

17
18

RMQ介绍Q?a >http://baike.baidu.com/view/1536346.htm
摘自某h文章:http://blog.sina.com.cn/s/blog_4d88e9860100cthl.html


]]>
U段树入??http://m.shnenglu.com/proyao/archive/2009/04/14/79839.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiMon, 13 Apr 2009 16:26:00 GMThttp://m.shnenglu.com/proyao/archive/2009/04/14/79839.htmlhttp://m.shnenglu.com/proyao/comments/79839.htmlhttp://m.shnenglu.com/proyao/archive/2009/04/14/79839.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/79839.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/79839.html好久没写q算法了Q添一个吧Q写一个线D|的入门知识,比较大众化?/p>

上次在湖大,其中的一道题数据很强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

 1void insert(int s,int t,int step)//要插入的U段的左端点和右端点、以及当前线D|中的某条U段
 2
 3{
 4
 5      if (s==a[step].left && t==a[step].right)
 6
 7      {
 8
 9            a[step].n++;//插入的线D匹配则此条U段的记?1
10
11            return;//插入l束q回
12
13      }

14
15      if (a[step].left==a[step].right)   return;//当前U段树的U段没有儿子Q插入结束返?/span>
16
17      int mid=(a[step].left+a[step].right)/2;
18
19      if (mid>=t)    insert(s,t,step*2);//如果中点在t的右边,则应该插入到左儿?/span>
20
21      else if (mid<s)    insert(s,t,step*2+1);//如果中点在s的左边,则应该插入到叛_?/span>
22
23      else//否则Q中点一定在s和t之间Q把待插U段分成两半分别插到左右儿子里面
24
25      {
26
27            insert(s,mid,step*2);
28
29            insert(mid+1,t,step*2+1);
30
31      }

32
33}

34
35

三条已知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 法[转]http://m.shnenglu.com/proyao/archive/2009/04/03/78878.htmlAcaini.yaoyaoziiAcaini.yaoyaoziiFri, 03 Apr 2009 13:50:00 GMThttp://m.shnenglu.com/proyao/archive/2009/04/03/78878.htmlhttp://m.shnenglu.com/proyao/comments/78878.htmlhttp://m.shnenglu.com/proyao/archive/2009/04/03/78878.html#Feedback0http://m.shnenglu.com/proyao/comments/commentRss/78878.htmlhttp://m.shnenglu.com/proyao/services/trackbacks/78878.htmlBellman-Ford 法及其优化

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法思想

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>

Bellman-Ford法程分ؓ三个阶段Q?/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>



]]>
˺ݺۺ88ۺϾþ| þùƷһƷ| þþþۺþ| þԭƷ| ƷþþþþĻ| þùƷ| ޾Ʒþþþþ| ձƷþþþĻ| þӰԺҹƬ| þˬˬƬav鷳 | þþۺ㽶ۺ| ŷþ18| ޾Ʒþһ| ˾þۺߴý| һaƬþëƬ| þ޾Ʒ˳ۺ| Ѹþ| þù׽| þۺϺݺۺϾþü | þþ뾫Ʒպý | 㽶þƵ| պŷþþwwwۺ | ޳˾þ| þùƷ77777| ˾þùѹۿƵ| AAƬѿƵþ| վþþ| ŷһþþƷ| þòþüӰԺwwwձ| þĻƷѩ | 99þùں;Ʒ1ӳ| þ99һ| ԭۺϾþô˾Ʒ| AVþþþò| þ99Ʒþþôѧ| ۺϳ˾þС˵ | þɫۺϼ| þþƷһ| 㽶97þ| Ʒպҹþ| ޹Ʒþþþ |