ACM算法计算几何基础
ACM几何2D讲解
已覆盖 未覆盖
完整的算法
• 有向弦构成多个有向多边形, 逆时针为正, 顺时针为负
• 弓形面积和与有向多边形面积和即为所求
时间复杂度
• 处理每一个圆
– 计算其他圆覆盖它的区间: O(n) – 排序并扫描得到各条有向弦: O(nlogn) – 计算各个弓形总面积: O(n)
• 这一步的总时间是O(n2logn) • 有向弦最多n2条, 计算有向多边形总面积为
• ACO2O1是平行四边形, 故AB=r1-r2, AC=d • 直角△ABC中, ∠BAC=arccos(r1-r2)/d
B
A
C
O1
O2
其他切点
• 对于每两个圆i, j, 需要求出四种切点相对于 二者的极角, 一共8个极角
• 算内公切线时AB=r1+r2 • 所求出的8个极角只是相对于O1O2的. 若
• 如果规定向量的起点都在原点,则可以用几何图 形表示向量加法和数量乘法
仿射几何
• 仿射几何(Affine Geometry)包括标量集合、 点集合和自由向量集合, 标量一般是实数, 自由向量表示方向和大小, 而位置不固定
仿射组合
• 一般来说点和数不能相乘, 点和点也不能相
加, 但
时以下情况是个例外
– 对任何一条边e,整个多边形在e 的一侧(如果是正方向,则必是 左侧)
• 星形多边形
– 存在多内部一点,能“看到”多边 形内所有点
– 所有满足定义要求的点组成的区 域称为“核”
– 由核和围绕着“核”的尖角构成, 总与圆同态
• 注意“看到”和“清晰看到”的区别
有向面积
• 左图:ABC成左手系,负面积 • 右图:ABC成右手系,正面积
北京大学ACM暑期课讲义-计算几何教程
计算几何教程
计算几何的恶心之处
代码长,难写。
需要讨论各种边界情况。后面所介绍的算
法,有些对于边界情况的处理很完美,不 需要再做讨论;有些则不然,需要自行处 理边界情况。
精度误差
二维矢量
2-Dimension Vector
矢量
既有大小又有方向的量。
算法演示
2 被弹出栈,3 进栈。
算法演示
没有点被弹出栈,4 进栈。
算法演示
4 被弹出栈,5 进栈。
算法演示
5 被弹出栈,6 进栈。
算法演示
6 被弹出栈,7 进栈。
算法演示
如此直到下凸壳被找到。
算法演示
倒序进行扫描找到上凸壳。
Graham 扫描的时间复杂度
这太傻缺了。算法的瓶颈在排序,所以时
总时间复杂度 O(N2 log N)。
算法扩展
SPOJ CIRUT
求恰好被覆盖 1 次、2 次、„、N 次的面积。
算法的本质在于对“裸露”部分进行处理。
这种方法也可以用于求很多圆与很多凸多 边形的面积并——但是情况复杂得多,要 讨论的情况也多得多。
三维矢量
3-Dimension Vector
总体来说讨论比较辛苦,写起来不算很难。
精度存在比较大的问题,而且半平面交的
题目一般都容许 O(N2) 算法,所以并不是 很常用。
半平面交练习题
POJ 1279 POJ 3525 POJ 2451 POJ 3384
求多边形的核。核中的点满足其到多边形边 界上任一点之间的线段只与多边形在那一点相交。 求凸多边形最大内切圆半径。 裸的半平面交。朱泽园专门为他的算法出的 题,要求 O(N log N) 算法。 求在凸多边形内部放两个半径为 r 的圆所能 覆盖的最大面积。两圆可以重叠,但不能与多边形相交。 需要用到旋转卡壳。
ACM必须掌握的算法
ACM必须的算法1.最短路(Floyd、Dijstra,BellmanFord)2.最小生成树(先写个prim,kruscal要用并查集,不好写)3.大数(高精度)加减乘除4.二分查找. (代码可在五行以内)5.叉乘、判线段相交、然后写个凸包.6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简)7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式.8. 调用系统的qsort, 技巧很多,慢慢掌握.9. 任意进制间的转换第二阶段:练习复杂一点,但也较常用的算法。
:1. 二分图匹配(匈牙利),最小路径覆盖2. 网络流,最小费用流。
3. 线段树.4. 并查集。
5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp6.博弈类算法。
博弈树,二进制法等。
7.最大团,最大独立集。
8.判断点在多边形内。
9. 差分约束系统. 10. 双向广度搜索、A*算法,最小耗散优先.相关的知识图论:路径问题 0/1边权最短路径 BFS 非负边权最短路径(Dijkstra)可以用Dijkstra解决问题的特征负边权最短路径Bellman-Ford Bellman-Ford的Yen-氏优化差分约束系统 Floyd 广义路径问题传递闭包极小极大距离 / 极大极小距离 EulerPath / Tour 圈套圈算法混合图的 Euler Path / TourHamilton Path / Tour 特殊图的Hamilton Path / Tour 构造生成树问题最小生成树第k小生成树最优比率生成树 0/1分数规划度限制生成树连通性问题强大的DFS算法无向图连通性割点割边二连通分支有向图连通性强连通分支 2-SAT最小点基有向无环图拓扑排序有向无环图与动态规划的关系二分图匹配问题一般图问题与二分图问题的转换思路最大匹配有向图的最小路径覆盖0 / 1矩阵的最小覆盖完备匹配最优匹配稳定婚姻网络流问题网络流模型的简单特征和与线性规划的关系最大流最小割定理最大流问题有上下界的最大流问题循环流最小费用最大流 / 最大费用最大流弦图的性质和判定组合数学解决组合数学问题时常用的思想逼近递推 / 动态规划概率问题Polya定理计算几何 / 解析几何计算几何的核心:叉积 / 面积解析几何的主力:复数基本形点直线,线段多边形凸多边形 / 凸包凸包算法的引进,卷包裹法Graham扫描法水平序的引进,共线凸包的补丁完美凸包算法相关判定两直线相交两线段相交点在任意多边形内的判定点在凸多边形内的判定经典问题最小外接圆近似O(n)的最小外接圆算法点集直径旋转卡壳,对踵点多边形的三角剖分数学 / 数论最大公约数Euclid算法扩展的Euclid算法同余方程 / 二元一次不定方程同余方程组线性方程组高斯消元法解mod 2域上的线性方程组整系数方程组的精确解法矩阵行列式的计算利用矩阵乘法快速计算递推关系分数分数树连分数逼近数论计算求N的约数个数求phi(N)求约数和快速数论变换……素数问题概率判素算法概率因子分解数据结构组织结构二叉堆左偏树二项树胜者树跳跃表样式图标斜堆reap统计结构树状数组虚二叉树线段树矩形面积并圆形面积并关系结构Hash表并查集路径压缩思想的应用 STL中的数据结构vectordequeset / map动态规划 / 记忆化搜索动态规划和记忆化搜索在思考方式上的区别最长子序列系列问题最长不下降子序列最长公共子序列最长公共不下降子序列一类NP问题的动态规划解法树型动态规划背包问题动态规划的优化四边形不等式函数的凸凹性状态设计规划方向线性规划常用思想二分最小表示法串KMPTrie结构后缀树/后缀数组 LCA/RMQ有限状态自动机理论排序选择/冒泡快速排序堆排序归并排序基数排序拓扑排序排序网络中级:一.基本算法:(1)C++的标准模版库的应用. (poj3096,poj3007)(2)较为复杂的模拟题的训练(poj3393,poj1472,poj3371,poj1027,poj2706)二.图算法:(1)差分约束系统的建立和求解. (poj1201,poj2983)(2)最小费用最大流(poj2516,poj2516,poj2195)(3)双连通分量(poj2942)(4)强连通分支及其缩点.(poj2186)(5)图的割边和割点(poj3352)(6)最小割模型、网络流规约(poj3308, )三.数据结构.(1)线段树. (poj2528,poj2828,poj2777,poj2886,poj2750)(2)静态二叉检索树. (poj2482,poj2352)(3)树状树组(poj1195,poj3321)(4)RMQ. (poj3264,poj3368)(5)并查集的高级应用. (poj1703,2492)(6)KMP算法. (poj1961,poj2406)四.搜索(1)最优化剪枝和可行性剪枝(2)搜索的技巧和优化 (poj3411,poj1724)(3)记忆化搜索(poj3373,poj1691)五.动态规划(1)较为复杂的动态规划(如动态规划解特别的施行商问题等)(poj1191,poj1054,poj3280,poj2029,poj2948,poj1925,poj3034)(2)记录状态的动态规划. (POJ3254,poj2411,poj1185)(3)树型动态规划(poj2057,poj1947,poj2486,poj3140)六.数学(1)组合数学:1.容斥原理.2.抽屉原理.3.置换群与Polya定理(poj1286,poj2409,poj3270,poj1026).4.递推关系和母函数.(2)数学.1.高斯消元法(poj2947,poj1487,poj2065,poj1166,poj1222)2.概率问题. (poj3071,poj3440)3.GCD、扩展的欧几里德(中国剩余定理) (poj3101)(3)计算方法.1.0/1分数规划. (poj2976)2.三分法求解单峰(单谷)的极值.3.矩阵法(poj3150,poj3422,poj3070)4.迭代逼近(poj3301)(4)随机化算法(poj3318,poj2454)(5)杂题.(poj1870,poj3296,poj3286,poj1095)七.计算几何学.(1)坐标离散化.(2)扫描线算法(例如求矩形的面积和周长并,常和线段树或堆一起使用).(poj1765,poj1177,poj1151,poj3277,po j2280,poj3004)(3)多边形的内核(半平面交)(poj3130,poj3335)(4)几何工具的综合应用.(poj1819,poj1066,poj2043,poj3227,poj2165,poj3429)高级:一.基本算法要求:(1)代码快速写成,精简但不失风格(poj2525,poj1684,poj1421,poj1048,poj2050,poj3306)(2)保证正确性和高效性. poj3434二.图算法:(1)度限制最小生成树和第K最短路. (poj1639)(2)最短路,最小生成树,二分图,最大流问题的相关理论(主要是模型建立和求解)(poj3155,poj2112,poj1966,poj3281,poj1087,poj2289,poj3216,poj2446(3)最优比率生成树. (poj2728)(4)最小树形图(poj3164)(5)次小生成树.(6)无向图、有向图的最小环三.数据结构.(1)trie图的建立和应用. (poj2778)(2)LCA和RMQ问题(LCA(最近公共祖先问题) 有离线算法(并查集+dfs) 和在线算法(RMQ+dfs)).(poj1330)(3)双端队列和它的应用(维护一个单调的队列,常常在动态规划中起到优化状态转移的目的). (poj2823)(4)左偏树(可合并堆).(5)后缀树(非常有用的数据结构,也是赛区考题的热点).(poj3415,poj3294)四.搜索(1)较麻烦的搜索题目训练(poj1069,poj3322,poj1475,poj1924,poj2049,poj3426)(2)广搜的状态优化:利用M进制数存储状态、转化为串用hash表判重、按位压缩存储状态、双向广搜、A*算法.(poj1768,poj1184,poj1872,poj1324,poj2046,poj1482)(3)深搜的优化:尽量用位运算、一定要加剪枝、函数参数尽可能少、层数不易过大、可以考虑双向搜索或者是轮换搜索、IDA*算法. (poj3131,poj2870,poj2286)五.动态规划(1)需要用数据结构优化的动态规划.(poj2754,poj3378,poj3017)(2)四边形不等式理论.(3)较难的状态DP(poj3133)六.数学(1)组合数学.1.MoBius反演(poj2888,poj2154)2.偏序关系理论.(2)博奕论.1.极大极小过程(poj3317,poj1085)2.Nim问题.七.计算几何学.(1)半平面求交(poj3384,poj2540)(2)可视图的建立(poj2966)(3)点集最小圆覆盖.(4)对踵点(poj2079)八.综合题.(poj3109,poj1478,poj1462,poj2729,poj2048,poj333 6,poj3315,poj2148,poj1263)初期:一.基本算法:(1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586)(3)递归和分治法. (4)递推.(5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法:(1)图的深度优先遍历和广度优先遍历.(2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)(poj1860,poj3259,poj1062,poj2253,poj1125,po j2240)(3)最小生成树算法(prim,kruskal)(poj1789,poj2485,poj1258,poj3026)(4)拓扑排序 (poj1094)(5)二分图的最大匹配 (匈牙利算法) (poj3041,poj3020)(6)最大流的增广路算法(KM算法). (poj1459,poj3436)三.数据结构.(1)串 (poj1035,poj3080,poj1936)(2)排序(快排、归并排(与逆序数有关)、堆排)(poj2388,poj2299)(3)简单并查集的应用.(4)哈希表和二分查找等高效查找法(数的Hash,串的Hash)(poj3349,poj3274,POJ2151,poj1840,poj2002,po j2503)(5)哈夫曼树(poj3253)(6)堆(7)trie树(静态建树、动态建树) (poj2513)四.简单搜索(1)深度优先搜索(poj2488,poj3083,poj3009,poj1321,poj2251)(2)广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)(3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)五.动态规划(1)背包问题. (poj1837,poj1276)(2)型如下表的简单DP(可参考lrj的书 page149):1.E[j]=opt{D+w(i,j)}(poj3267,poj1836,poj1260,poj2533)2.E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1 ]+zij} (最长公共子序列)(poj3176,poj1080,poj1159)3.C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.(最优二分检索树问题)六.数学(1)组合数学:1.加法原理和乘法原理.2.排列组合.3.递推关系.(POJ3252,poj1850,poj1019,poj1942)(2)数论.1.素数与整除问题2.进制位.3.同余模运算.(poj2635, poj3292,poj1845,poj2115)(3)计算方法.1.二分法求解单调函数相关知识.(poj3273,poj3258,poj1905,poj3122)七.计算几何学.(1)几何公式.(2)叉积和点积的运用(如线段相交的判定,点到线段的距离等). (poj2031,poj1039)(3)多边型的简单算法(求面积)和相关判定(点在多边型内,多边型是否相交)(poj1408,poj1584)(4)凸包. (poj2187,poj1113)。
ACM计算几何题目总结及分类
COJ/oj/prepare.do?fun=viewProblem&pid=1011/oj/prepare.do?fun=viewProblem&pid=1024/oj/prepare.do?fun=viewProblem&pid=1034/oj/prepare.do?fun=viewProblem&pid=1035/oj/prepare.do?fun=viewProblem&pid=1036/oj/prepare.do?fun=viewProblem&pid=1037/oj/prepare.do?fun=viewProblem&pid=1038/oj/prepare.do?fun=viewProblem&pid=1078/oj/prepare.do?fun=viewProblem&pid=1137/oj/prepare.do?fun=viewProblem&pid=1172/oj/prepare.do?fun=viewProblem&pid=1190/oj/prepare.do?fun=viewProblem&pid=1211/oj/prepare.do?fun=viewProblem&pid=1230/oj/prepare.do?fun=viewProblem&pid=1231/oj/prepare.do?fun=viewProblem&pid=1249:8080/COJ/prepare.do?fun=viewProblem&pid=1257:8080/COJ/prepare.do?fun=viewProblem&pid=1260FOJHotter Colder/problem.php?pid=1014求线段的中位线,线段相交求交点,求凸多边形的面积,无归之室/problem.php?pid=1016本题精度要求非常高,用三角函数的话,很容易就wa..Reflections/problem.php?pid=1035求一条射线遇到圆后的反射光,即圆和直线求交点,求点关于交点法线的对称点。
ACM程序竞赛计算几何超全模板
/*计算几何目录㈠点的基本运算1. 平面上两点之间距离12. 判断两点是否重合13. 矢量叉乘14. 矢量点乘25. 判断点是否在线段上26. 求一点饶某点旋转后的坐标27. 求矢量夹角2㈡线段及直线的基本运算1. 点与线段的关系32. 求点到线段所在直线垂线的垂足43. 点到线段的最近点44. 点到线段所在直线的距离45. 点到折线集的最近距离46. 判断圆是否在多边形内57. 求矢量夹角余弦58. 求线段之间的夹角59. 判断线段是否相交610.判断线段是否相交但不交在端点处611.求线段所在直线的方程612.求直线的斜率713.求直线的倾斜角714.求点关于某直线的对称点715.判断两条直线是否相交及求直线交点716.判断线段是否相交,如果相交返回交点7㈢多边形常用算法模块1. 判断多边形是否简单多边形82. 检查多边形顶点的凸凹性93. 判断多边形是否凸多边形94. 求多边形面积95. 判断多边形顶点的排列方向,方法一106. 判断多边形顶点的排列方向,方法二107. 射线法判断点是否在多边形内108. 判断点是否在凸多边形内119. 寻找点集的graham算法1210.寻找点集凸包的卷包裹法1311.判断线段是否在多边形内1412.求简单多边形的重心1513.求凸多边形的重心1714.求肯定在给定多边形内的一个点1715.求从多边形外一点出发到该多边形的切线1816.判断多边形的核是否存在19㈣圆的基本运算1 .点是否在圆内202 .求不共线的三点所确定的圆21㈤矩形的基本运算1.已知矩形三点坐标,求第4点坐标22㈥常用算法的描述22㈦补充1.两圆关系:242.判断圆是否在矩形内:243.点到平面的距离:254.点是否在直线同侧:255.镜面反射线:256.矩形包含:267.两圆交点:278.两圆公共面积:289. 圆和直线关系:2910. 内切圆:3011. 求切点:3112. 线段的左右旋:3113.公式:32*//* 需要包含的头文件*/#include <cmath >/* 常用的常量定义*/const double INF = 1E200const double EP = 1E-10const int MAXV = 300const double PI = 3.14159265/* 基本几何结构*/struct POINT{double x;double y;POINT(double a=0, double b=0) { x=a; y=b;} //constructor};struct LINESEG{POINT s;POINT e;LINESEG(POINT a, POINT b) { s=a; e=b;}LINESEG() { }};struct LINE // 直线的解析方程a*x+b*y+c=0 为统一表示,约定a >= 0{double a;double b;double c;LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;}};/*********************** ** 点的基本运算** ***********************/double dist(POINT p1,POINT p2) // 返回两点之间欧氏距离{return( sqrt( (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y) ) );}bool equal_point(POINT p1,POINT p2) // 判断两个点是否重合{return ( (abs(p1.x-p2.x)<EP)&&(abs(p1.y-p2.y)<EP) );}/****************************************************************************** r=multiply(sp,ep,op),得到(sp-op)和(ep-op)的叉积r>0:ep在矢量opsp的逆时针方向;r=0:opspep三点共线;r<0:ep在矢量opsp的顺时针方向******************************************************************************* /double multiply(POINT sp,POINT ep,POINT op){return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));}/*r=dotmultiply(p1,p2,op),得到矢量(p1-op)和(p2-op)的点积,如果两个矢量都非零矢量r<0:两矢量夹角为锐角;r=0:两矢量夹角为直角;r>0:两矢量夹角为钝角******************************************************************************* /double dotmultiply(POINT p1,POINT p2,POINT p0){return ((p1.x-p0.x)*(p2.x-p0.x)+(p1.y-p0.y)*(p2.y-p0.y));}/****************************************************************************** 判断点p是否在线段l上条件:(p在线段l所在的直线上) && (点p在以线段l为对角线的矩形内)******************************************************************************* /bool online(LINESEG l,POINT p){return( (multiply(l.e,p,l.s)==0) &&( ( (p.x-l.s.x)*(p.x-l.e.x)<=0 )&&( (p.y-l.s.y)*(p.y-l.e.y)<=0 ) ) ); }// 返回点p以点o为圆心逆时针旋转alpha(单位:弧度)后所在的位置POINT rotate(POINT o,double alpha,POINT p){POINT tp;p.x-=o.x;p.y-=o.y;tp.x=p.x*cos(alpha)-p.y*sin(alpha)+o.x;tp.y=p.y*cos(alpha)+p.x*sin(alpha)+o.y;return tp;}/* 返回顶角在o点,起始边为os,终止边为oe的夹角(单位:弧度)角度小于pi,返回正值角度大于pi,返回负值可以用于求线段之间的夹角原理:r = dotmultiply(s,e,o) / (dist(o,s)*dist(o,e))r'= multiply(s,e,o)r >= 1 angle = 0;r <= -1 angle = -PI-1<r<1 && r'>0 angle = arccos(r)-1<r<1 && r'<=0 angle = -arccos(r)*/double angle(POINT o,POINT s,POINT e){double cosfi,fi,norm;double dsx = s.x - o.x;double dsy = s.y - o.y;double dex = e.x - o.x;double dey = e.y - o.y;cosfi=dsx*dex+dsy*dey;norm=(dsx*dsx+dsy*dsy)*(dex*dex+dey*dey);cosfi /= sqrt( norm );if (cosfi >= 1.0 ) return 0;if (cosfi <= -1.0 ) return -3.1415926;fi=acos(cosfi);if (dsx*dey-dsy*dex>0) return fi; // 说明矢量os 在矢量oe的顺时针方向return -fi;}/*****************************\* ** 线段及直线的基本运算** *\*****************************//* 判断点与线段的关系,用途很广泛本函数是根据下面的公式写的,P是点C到线段AB所在直线的垂足AC dot ABr = ---------||AB||^2(Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)= -------------------------------L^2r has the following meaning:r=0 P = Ar=1 P = Br<0 P is on the backward extension of ABr>1 P is on the forward extension of AB0<r<1 P is interior to AB*/double relation(POINT p,LINESEG l){LINESEG tl;tl.s=l.s;tl.e=p;return dotmultiply(tl.e,l.e,l.s)/(dist(l.s,l.e)*dist(l.s,l.e));}// 求点C到线段AB所在直线的垂足PPOINT perpendicular(POINT p,LINESEG l){double r=relation(p,l);POINT tp;tp.x=l.s.x+r*(l.e.x-l.s.x);tp.y=l.s.y+r*(l.e.y-l.s.y);return tp;}/* 求点p到线段l的最短距离,并返回线段上距该点最近的点np注意:np是线段l上到点p最近的点,不一定是垂足*/double ptolinesegdist(POINT p,LINESEG l,POINT &np){double r=relation(p,l);if(r<0){np=l.s;return dist(p,l.s);}if(r>1){np=l.e;return dist(p,l.e);}np=perpendicular(p,l);return dist(p,np);}// 求点p到线段l所在直线的距离,请注意本函数与上个函数的区别double ptoldist(POINT p,LINESEG l){return abs(multiply(p,l.e,l.s))/dist(l.s,l.e);}/* 计算点到折线集的最近距离,并返回最近点.注意:调用的是ptolineseg()函数*/double ptopointset(int vcount,POINT pointset[],POINT p,POINT &q) {int i;double cd=double(INF),td;LINESEG l;POINT tq,cq;for(i=0;i<vcount-1;i++)l.s=pointset[i];l.e=pointset[i+1];td=ptolinesegdist(p,l,tq);if(td<cd){cd=td;cq=tq;}}q=cq;return cd;}/* 判断圆是否在多边形内.ptolineseg()函数的应用2 */bool CircleInsidePolygon(int vcount,POINT center,double radius,POINT polygon[]){POINT q;double d;q.x=0;q.y=0;d=ptopointset(vcount,polygon,center,q);if(d<radius||fabs(d-radius)<EP)return true;elsereturn false;}/* 返回两个矢量l1和l2的夹角的余弦(-1 --- 1)注意:如果想从余弦求夹角的话,注意反余弦函数的定义域是从0到pi */double cosine(LINESEG l1,LINESEG l2){return (((l1.e.x-l1.s.x)*(l2.e.x-l2.s.x) +(l1.e.y-l1.s.y)*(l2.e.y-l2.s.y))/(dist(l1.e,l1.s)*dist(l2.e,l2.s))) );}// 返回线段l1与l2之间的夹角单位:弧度范围(-pi,pi)double lsangle(LINESEG l1,LINESEG l2){POINT o,s,e;o.x=o.y=0;s.x=l1.e.x-l1.s.x;s.y=l1.e.y-l1.s.y;e.x=l2.e.x-l2.s.x;e.y=l2.e.y-l2.s.y;return angle(o,s,e);// 如果线段u和v相交(包括相交在端点处)时,返回true////判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) ×( Q2 - Q1 ) * ( Q2 - Q1 ) ×( P2 - Q1 ) >= 0。
ACM计算几何模板__HIT_jerrybond.
ACM@HIT
Au分 1.几何公式.............................................................................................................................................. 5 1.1 三角形 ....................................................................................................................................... 5 1.2 四边形 ....................................................................................................................................... 5 1.3 正 n 边形 ...................................................................................................................................5 1.4 圆............................................................................................................................................... 5 1.5 棱柱.........................................
ACM计算几何模板__HIT_jerrybond.
ACd
1
基础部分 1.几何公式.............................................................................................................................................. 5 1.1 三角形 ....................................................................................................................................... 5 1.2 四边形 ....................................................................................................................................... 5 1.3 正 n 边形 ...................................................................................................................................5 1.4 圆............................................................................................................................................... 5 1.5 棱柱.......................................
计算几何--ACM
三计算模型
规定RAM的原始运算如下: 1)算术运算 2)两个实数之间的比较 3)间接寻址及求根运算,三角函数运算,指 数函数运算,对数函数运算。 执行每种运算耗费一个时间单位。
四常见计算几何基本问题
• 矢量的概念
• • • • • • • • • • • • • • • • • • • • • • • • • • • •
基本问题(续)
• 在实际编程中,没有必要计算所有的交点,首先应判断线段和多边形的边是否内 交,倘若线段和多边形的某条边内交则线段一定在多边形外;如果线段和多边形 的每一条边都不内交,则线段和多边形的交点一定是线段的端点或者多边形的顶 点,只要判断点是否在线段上就可以了。
得出算法如下: if 线端PQ的端点不都在多边形内 then return false; 点集pointSet初始化为空; for 多边形的每条边s do if 线段的某个端点在s上 then 将该端点加入pointSet; else if s的某个端点在线段PQ上 then 将该端点加入pointSet; else if s和线段PQ相交 // 这时候已经可以肯定是内交了 then return false; 将pointSet中的点按照X-Y坐标排序; for pointSet中每两个相邻点 pointSet[i] , pointSet[ i+1] do if pointSet[i] , pointSet[ i+1] 的中点不在多边形中 then return false; return true; 这个过程中的排序因为交点数目肯定远小于多边形的顶点数目n,所以最多是 常数级的复杂度,几乎可以忽略不计。因此算法的时间复杂度也是O(n)。
基本问题(续)
基本问题(续)
ACMer需要掌握的算法讲解
ACM主要算法介绍初期篇一、基本算法(1)枚举(poj1753, poj2965)(2)贪心(poj1328, poj2109, poj2586)(3)递归和分治法(4)递推(5)构造法(poj3295)(6)模拟法(poj1068, poj2632, poj1573, poj2993, poj2996)二、图算法(1)图的深度优先遍历和广度优先遍历(2)最短路径算法(dijkstra, bellman-ford, floyd, heap+dijkstra)(poj1860, poj3259, poj1062, poj2253, poj1125, poj2240)(3)最小生成树算法(prim, kruskal)(poj1789, poj2485, poj1258, poj3026)(4)拓扑排序(poj1094)(5)二分图的最大匹配(匈牙利算法)(poj3041, poj3020)(6)最大流的增广路算法(KM算法)(poj1459, poj3436)三、数据结构(1)串(poj1035, poj3080, poj1936)(2)排序(快排、归并排(与逆序数有关)、堆排)(poj2388, poj2299)(3)简单并查集的应用(4)哈希表和二分查找等高效查找法(数的Hash, 串的Hash)(poj3349, poj3274, POJ2151, poj1840, poj2002, poj2503)(5)哈夫曼树(poj3253)(6)堆(7)trie树(静态建树、动态建树)(poj2513)四、简单搜索(1)深度优先搜索(poj2488, poj3083, poj3009, poj1321, poj2251)(2)广度优先搜索(poj3278, poj1426, poj3126, poj3087, poj3414)(3)简单搜索技巧和剪枝(poj2531, poj1416, poj2676, 1129)五、动态规划(1)背包问题(poj1837, poj1276)(2)型如下表的简单DP(可参考lrj的书page149):1.E[j]=opt{D+w(i,j)} (poj3267, poj1836, poj1260, poj2533)2.E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij} (最长公共子序列)(poj3176, poj1080, poj1159)3.C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]} (最优二分检索树问题)六、数学(1)组合数学1.加法原理和乘法原理2.排列组合3.递推关系(poj3252, poj1850, poj1019, poj1942)(2)数论1.素数与整除问题2.进制位3.同余模运算(poj2635, poj3292, poj1845, poj2115)(3)计算方法1.二分法求解单调函数相关知识(poj3273, poj3258, poj1905, poj3122)七、计算几何学(1)几何公式(2)叉积和点积的运用(如线段相交的判定,点到线段的距离等)(poj2031, poj1039)(3)多边型的简单算法(求面积)和相关判定(点在多边型内,多边型是否相交)(poj1408, poj1584)(4)凸包(poj2187, poj1113)中级篇一、基本算法(1)C++的标准模版库的应用(poj3096, poj3007)(2)较为复杂的模拟题的训练(poj3393, poj1472, poj3371, poj1027,poj2706)二、图算法(1)差分约束系统的建立和求解(poj1201, poj2983)(2)最小费用最大流(poj2516, poj2195)(3)双连通分量(poj2942)(4)强连通分支及其缩点(poj2186)(5)图的割边和割点(poj3352)(6)最小割模型、网络流规约(poj3308)三、数据结构(1)线段树(poj2528, poj2828, poj2777, poj2886, poj2750)(2)静态二叉检索树(poj2482, poj2352)(3)树状树组(poj1195, poj3321)(4)RMQ(poj3264, poj3368)(5)并查集的高级应用(poj1703, 2492)(6)KMP算法(poj1961, poj2406)四、搜索(1)最优化剪枝和可行性剪枝(2)搜索的技巧和优化(poj3411, poj1724)(3)记忆化搜索(poj3373, poj1691)五、动态规划(1)较为复杂的动态规划(如动态规划解特别的施行商问题等)(poj1191, poj1054, poj3280, poj2029, poj2948, poj1925, poj3034)(2)记录状态的动态规划(poj3254, poj2411, poj1185)(3)树型动态规划(poj2057, poj1947, poj2486, poj3140)六、数学(1)组合数学1.容斥原理2.抽屉原理3.置换群与Polya定理(poj1286, poj2409, poj3270, poj1026)4.递推关系和母函数(2)数学1.高斯消元法(poj2947, poj1487, poj2065, poj1166, poj1222)2.概率问题(poj3071, poj3440)3.GCD、扩展的欧几里德(中国剩余定理)(poj3101)(3)计算方法1.0/1分数规划(poj2976)2.三分法求解单峰(单谷)的极值3.矩阵法(poj3150, poj3422, poj3070)4.迭代逼近(poj3301)(4)随机化算法(poj3318, poj2454)(5)杂题(poj1870, poj3296, poj3286, poj1095)七、计算几何学(1)坐标离散化(2)扫描线算法(例如求矩形的面积和周长,并常和线段树或堆一起使用)(poj1765, poj1177, poj1151, poj3277, poj2280, poj3004)(3)多边形的内核(半平面交)(poj3130, poj3335)(4)几何工具的综合应用(poj1819, poj1066, poj2043, poj3227, poj2165, poj3429)高级篇一、基本算法要求(1)代码快速写成,精简但不失风格(poj2525, poj1684, poj1421,poj1048, poj2050, poj3306)(2)保证正确性和高效性(poj3434)二、图算法(1)度限制最小生成树和第K最短路(poj1639)(2)最短路,最小生成树,二分图,最大流问题的相关理论(主要是模型建立和求解)(poj3155, poj2112, poj1966, poj3281, poj1087, poj2289, poj3216, poj2446)(3)最优比率生成树(poj2728)(4)最小树形图(poj3164)(5)次小生成树(6)无向图、有向图的最小环三、数据结构(1)trie图的建立和应用(poj2778)(2)LCA和RMQ问题(LCA(最近公共祖先问题),有离线算法(并查集+dfs)和在线算法(RMQ+dfs))(poj1330)(3)双端队列和它的应用(维护一个单调的队列,常常在动态规划中起到优化状态转移的目的)(poj2823)(4)左偏树(可合并堆)(5)后缀树(非常有用的数据结构,也是赛区考题的热点)(poj3415,poj3294)四、搜索(1)较麻烦的搜索题目训练(poj1069, poj3322, poj1475, poj1924,poj2049, poj3426)(2)广搜的状态优化:利用M进制数存储状态、转化为串用hash表判重、按位压缩存储状态、双向广搜、A*算法(poj1768, poj1184, poj1872, poj1324, poj2046, poj1482)(3)深搜的优化:尽量用位运算、一定要加剪枝、函数参数尽可能少、层数不易过大、可以考虑双向搜索或者是轮换搜索、IDA*算法(poj3131, poj2870, poj2286)五、动态规划(1)需要用数据结构优化的动态规划(poj2754, poj3378, poj3017)(2)四边形不等式理论(3)较难的状态DP(poj3133)六、数学(1)组合数学1.MoBius反演(poj2888, poj2154)2.偏序关系理论(2)博奕论1.极大极小过程(poj3317, poj1085)2.Nim问题七、计算几何学(1)半平面求交(poj3384, poj2540)(2)可视图的建立(poj2966)(3)点集最小圆覆盖(4)对踵点(poj2079)八、综合题(poj3109, poj1478, poj1462, poj2729, poj2048, poj3336, poj3315, poj2148, poj1263)附录:POJ是“北京大学程序在线评测系统”(Peking University Online Judge)的缩写,是个提供编程题目的网站,兼容Pascal、C、C++、Java、Fortran等多种语言。
ACM常用算法
ACM常用算法ACM常考算法ACM小组内部预定函数Ver 2.0 by IcyFenix数学问题:1.精度计算――大数2.精度计算――乘法(大数3.精度计算――乘法(大阶乘5.精度计算――减法9.快速傅立叶变换(FFT)字符串处理:1.字符串替换计算几何:1.叉乘法求任意多边形面积5.射向法判断点是否在多边形内部9.点到线段最短距离数论:1.x的二进制长度5.求解模线性方程组(中国余数定理) 图论:1.Prim算法求最小生成树排序/查找:1.快速排序数据结构:1.顺序队列乘小数)6.任意进制转换10.Ronberg算法计算积分2.字符串查找2.求三角形面积6.判断点是否在线段上10.求两直线的交点2.返回x的二进制表示中从低到高的第i位6.筛法素数产生器2.Dijkstra算法求单源最短路径2.希尔排序2.顺序栈数乘大数)4.精度计算――加法7.最大公约数、最小公倍数8.组合序列11.行列式计算12.求排列组合数3.字符串截取3.两矢量间角度4.两点距离(2D、3D)7.判断两线段是否相交8.判断线段与直线是否相交11.判断一个封闭图形是12.Graham扫描法寻凹集还是凸集找凸包3.模取幂运算4.求解模线性方程7.判断一个数是否素数3.Bellman-ford算法求4.Floyd算法求每对单源最短路径节点间最短路径3.选择法排序4.二分查找3.链表4.链栈ACM常考算法5.二叉树一、数学问题1.精度计算――大数阶乘语法:int result=factorial(int n); 参数:n:n 的阶乘返回阶乘结果的位数值:注意:源程序:本程序直接输出n!的结果,需要返回结果请保留long a[] 需要math.hint factorial(int n){long a[__];int i,j,l,c,m=0,w; a=1;for(i=1;ii++) { c=0;for(j=0;jj++) {a[j]=a[j]*i+c; c=a[j]/__; a[j]=a[j]%__; }if(c0) {m++;a[m]=c;} }w=m*4+log10(a[m])+1;printf(“\n%ld",a[m]);for(i=m-1;ii--) printf("%4.4ld",a[i]);return w; }2.精度计算――乘法(大数乘小数)语法:mult(char c[],char t[],int m); 参数:c[]:被乘数,用字符串表示,位数不限t[]:结果,用字符串表示m:乘数,限定10以内返回null 值:注意:需要string.hACM常考算法源程序:void mult(char c[],char t[],int m) {int i,l,k,flag,add=0; char s; l=strlen(c);for (i=0;ii++)s[l-i-1]=c[i]-'0';for (i=0;ii++) {k=s[i]*m+add;if (k=10) {s[i]=k%10;add=k/10;flag=1;}else {s[i]=k;flag=0;add=0;} }if (flag) {l=i+1;s[i]=add;}else l=i; for (i=0;ii++)t[l-1-i]=s[i]+'0'; t[l]='\0'; }3.精度计算――乘法(大数乘大数)语法:mult(char a[],char b[],char s[]); 参数:a[]:被乘数,用字符串表示,位数不限b[]:乘数,用字符串表示,位数不限t[]:结果,用字符串表示返回null 值:注意:源程序:空间复杂度为o(n^2) 需要string.hvoid mult(char a[],char b[],char s[]) {int i,j,k=0,alen,blen,sum=0,res={0},flag=0; char result;alen=strlen(a);blen=strlen(b);for (i=0;ialen;i++)for (j=0;jblen;j++) res[i][j]=(a[i]-'0')*(b[j]-'0'); for (i=alen-1;ii--) {for (j=blen-1;jj--) sum=sum+res[i+blen-j-1][j]; result[k]=sum%10; k=k+1;ACM常考算法sum=sum/10; }for (i=blen-2;ii--) {for (j=0;jj++) sum=sum+res[i-j][j]; result[k]=sum%10; k=k+1;sum=sum/10; }if (sum!=0) {result[k]=sum;k=k+1;} for (i=0;ii++) result[i]+='0';for (i=k-1;ii--) s[i]=result[k-1-i]; s[k]='\0';while(1) {if (strlen(s)!=strlen(a)s=='0') strcpy(s,s+1); elsebreak; } }4.精度计算――加法语法:add(char a[],char b[],char s[]); 参数:a[]:被乘数,用字符串表示,位数不限b[]:乘数,用字符串表示,位数不限t[]:结果,用字符串表示返回null 值:注意:源程序:空间复杂度为o(n^2) 需要string.hvoid add(char a[],char b[],char back[]) {int i,j,k,up,x,y,z,l; char *c; if (strlen(a)strlen(b)) l=strlen(a)+2;elsel=strlen(b)+2; c=(char *) malloc(l*sizeof(char)); i=strlen(a)-1; j=strlen(b)-1; k=0;up=0;while(i=0||j=0) {if(i0) x='0'; else x=a[i];ACM常考算法if(j0) y='0'; else y=b[j]; z=x-'0'+y-'0'; if(up) z+=1;if(z9) {up=1;z%=10;} else up=0; c[k++]=z+'0'; i--;j--; }if(up) c[k++]='1'; i=0;c[k]='\0';for(k-=1;kk--) back[i++]=c[k]; back[i]='\0'; }5.精度计算――减法语法:sub(char s1[],char s2[],char t[]); 参数:s1[]:被减数,用字符串表示,位数不限s2[]:减数,用字符串表示,位数不限t[]:结果,用字符串表示返回null 值:注意:源程序:默认s1=s2,程序未处理负数情况需要string.hvoid sub(char s1[],char s2[],char t[]) {int i,l2,l1,k;l2=strlen(s2);l1=strlen(s1); t[l1]='\0';l1--;for (i=l2-1;ii--,l1--) {if (s1[l1]-s2[i]=0)t[l1]=s1[l1]-s2[i]+'0'; else {t[l1]=10+s1[l1]-s2[i]+'0'; s1[l1-1]=s1[l1-1]-1; } } k=l1;while(s1[k]0) {s1[k]+=10;s1[k-1]-=1;k--;} while(l1=0) {t[l1]=s1[l1];l1--;} loop:if (t=='0') {ACM常考算法l1=strlen(s1);for (i=0;il1-1;i++) t[i]=t[i+1]; t[l1-1]='\0'; goto loop; }if (strlen(t)==0) {t='0';t='\0';} }6.任意进制转换语法:conversion(char s1[],char s2[],long d1,long d2); 参数:s[]:原进制数字,用字符串表示s2[]:转换结果,用字符串表示d1:原进制数d2:需要转换到的进制数返回null 值:注意:源程序:高于9的位数用大写'A'~'Z'表示,2~16位进制通过验证void conversion(char s[],char s2[],long d1,long d2) {long i,j,t,num; char c; num=0;for (i=0;s[i]!='\0';i++) {if (s[i]='9's[i]='0') t=s[i]-'0';else t=s[i]-'A'+10;num=num*d1+t; } i=0; while(1) {t=num%d2;if (t=9) s2[i]=t+'0';else s2[i]=t+'A'-10; num/=d2;if (num==0)break; i++; }for (j=0;jj++){c=s2[j];s2[j]=s[i-j];s2[i-j]=c;} s2[i+1]='\0'; }7.最大公约数、最小公倍数ACM常考算法语法:resulet=hcf(int a,int b)、result=lcd(int a,int b) 参数:a:int a,求最大公约数或最小公倍数b:int b,求最大公约数或最小公倍数返回返回最大公约数(hcf)或最小公倍数(lcd)值:注意:源程序:lcd 需要连同hcf 使用int hcf(int a,int b) {int r=0; while(b!=0) {r=a%b; a=b; b=r; }return(a); }lcd(int u,int v,int h) {return(u*v/h); }8.组合序列语法:m_of_n(int m,int n1,int m1,int* a,int head) 参数:m:组合数C的上参数n1:组合数C的下参数m1:组合数C的上参数,递归之用*a:1~n的整数序列数组head:头指针返回null 值:注意:源程序:*a需要自行产生初始调用时,m=m1、head=0调用例子:求C(m,n)序列:m_of_n(m,n,m,a,0);ACM常考算法void m_of_n(int m,int n1,int m1,int* a,int head) {int i,t;if(m10 || m1n1)return; if(m1==n1) {for(i=0;ii++) couta[i]' '; // 输出序列cout'\n'; return; }m_of_n(m,n1-1,m1,a,head); // 递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t; m_of_n(m,n1-1,m1-1,a,head+1); // 再次递归调用t=a[head];a[head]=a[n1-1+head];a[n1-1+head]=t; }9.快速傅立叶变换(FFT)语法:kkfft(double pr[],double pi[],int n,int k,double fr[],double fi[],int l,int il); 参数:pr[n]:输入的实部pi[n]:数入的虚部n,k:满足n=2^k fr[n]:输出的实部fi[n]:输出的虚部l:逻辑开关,0 FFT,1 ifFTil:逻辑开关,0 输出按实部/虚部;1 输出按模/幅角返回null 值:注意:源程序:需要math.hvoid kkfft(pr,pi,n,k,fr,fi,l,il)int n,k,l,il;double pr[],pi[],fr[],fi[]; {int it,m,is,i,j,nv,l0;double p,q,s,vr,vi,poddr,poddi; for (it=0; it=n-1; it++) {m=it; is=0;for (i=0; i=k-1; i++){j=m/2; is=2*is+(m-2*j); m=j;} fr[it]=pr[is]; fi[it]=pi[is]; }pr=1.0; pi=0.0; p=6.__-__6/(1.0*n);pr=cos(p); pi=-sin(p);ACM常考算法if (l!=0) pi=-pi; for (i=2; i=n-1; i++) {p=pr[i-1]*pr; q=pi[i-1]*pi;s=(pr[i-1]+pi[i-1])*(pr+pi); pr[i]=p-q; pi[i]=s-p-q; }for (it=0; it=n-2; it=it+2) {vr=fr[it]; vi=fi[it];fr[it]=vr+fr[it+1]; fi[it]=vi+fi[it+1];fr[it+1]=vr-fr[it+1]; fi[it+1]=vi-fi[it+1]; }m=n/2; nv=2;for (l0=k-2; l0 l0--) {m=m/2; nv=2*nv;for (it=0; it=(m-1)*nv; it=it+nv) for (j=0; j=(nv/2)-1; j++) {p=pr[m*j]*fr[it+j+nv/2]; q=pi[m*j]*fi[it+j+nv/2]; s=pr[m*j]+pi[m*j];s=s*(fr[it+j+nv/2]+fi[it+j+nv/2]); poddr=p-q; poddi=s-p-q;fr[it+j+nv/2]=fr[it+j]-poddr; fi[it+j+nv/2]=fi[it+j]-poddi;fr[it+j]=fr[it+j]+poddr; fi[it+j]=fi[it+j]+poddi; } }if (l!=0)for (i=0; i=n-1; i++) {fr[i]=fr[i]/(1.0*n); fi[i]=fi[i]/(1.0*n); } if (il!=0)for (i=0; i=n-1; i++) {pr[i]=sqrt(fr[i]*fr[i]+fi[i]*fi[i]); if (fabs(fr[i])0.000001*fabs(fi[i])) {if ((fi[i]*fr[i])0) pi[i]=90.0; else pi[i]=-90.0; } elsepi[i]=atan(fi[i]/fr[i])*360.0/6.__-__6; } return; }10.Ronberg算法计算积分语法:result=integral(double a,double b);ACM常考算法参数:a:积分上限b:积分下限function积分函数f:返回值:f在(a,b)之间的积分值注意:源程序:function f(x)需要自行修改,程序中用的是sina(x)/x 需要math.h 默认精度要求是1e-5double f(double x) {return sin(x)/x; //在这里插入被积函数}double integral(double a,double b) {double h=b-a;double t1=(1+f(b))*h/2.0; int k=1;double r1,r2,s1,s2,c1,c2,t2; loop:double s=0.0;double x=a+h/2.0; while(xb) {s+=f(x); x+=h; }t2=(t1+h*s)/2.0; s2=t2+(t2-t1)/3.0; if(k==1) {k++;h/=2.0;t1=t2;s1=s2; goto loop; }c2=s2+(s2-s1)/15.0; if(k==2){c1=c2;k++;h/=2.0; t1=t2;s1=s2; goto loop; }r2=c2+(c2-c1)/63.0; if(k==3){r1=r2; c1=c2;k++; h/=2.0;t1=t2;s1=s2; goto loop; }while(fabs(1-r1/r2)1e-5){ r1=r2;c1=c2;k++; h/=2.0;ACM常考算法t1=t2;s1=s2; goto loop; }return r2; }11.行列式计算语法:result=js(int s[][],int n) 参数:s[][]:行列式存储数组n:行列式维数,递归用返回行列式值值:注意:源程序:函数中常数N为行列式维度,需自行定义int js(s,n)int s[][N],n; {int z,j,k,r,total=0; int b[N][N];/*b[N][N]用于存放,在矩阵s[N][N]中元素s的余子式*/if(n2) {for(z=0;zz++) {for(j=0;jj++)for(k=0;kk++)if(k=z) b[j][k]=s[j+1][k+1]; else b[j][k]=s[j+1][k];if(z%2==0) r=s[z]*js(b,n-1); /*递归调用*/ else r=(-1)*s[z]*js(b,n-1); total=total+r; } }else if(n==2)total=s*s-s*s; return total; }12.求排列组合数语法:result=P(long n,long m); / result=long C(long n,long m); 参数:m:排列组合的上系数n:排列组合的下系数返回排列组合数ACM常考算法值:注意:源程序:符合数学规则:m=nlong P(long n,long m) {long p=1; while(m!=0){p*=n;n--;m--;} return p; }long C(long n,long m) {long i,c=1; i=m;while(i!=0){c*=n;n--;i--;} while(m!=0) {c/=m;m--;} return c; }二、字符串处理1.字符串替换语法:replace(char str[],char key[],char swap[]); 参数:str[]:在此源字符串进行替换操作key[]:被替换的字符串,不能为空串swap[]替换的字符串,可以为空串,为空串表示在源字符中删除key[] :返回null 值:注意:源程序:默认str[]长度小于1000,如否,重新设定设定tmp大小需要string.hvoid replace(char str[],char key[],char swap[]) {int l1,l2,l3,i,j,flag; char tmp; l1=strlen(str); l2=strlen(key);l3=strlen(swap);for (i=0;i=l1-l2;i++)ACM常考算法{flag=1;for (j=0;jj++)if (str[i+j]!=key[j]) {flag=0;break;} if (flag) {strcpy(tmp,str);strcpy(tmp[i],swap);strcpy(tmp[i+l3],str[i+l2]); strcpy(str,tmp); i+=l3-1;l1=strlen(str); } } }2.字符串查找语法:result=strfind(char str[],char key[]); 参数:str[]:在此源字符串进行查找操作key[]:被查找的字符串,不能为空串返回如果查找成功,返回key在str中第一次出现的位置,否则返回-1 值:注意:源程序:需要string.hint strfind(char str[],char key[]) {int l1,l2,i,j,flag; l1=strlen(str); l2=strlen(key);for (i=0;i=l1-l2;i++) {flag=1;for (j=0;jj++)if (str[i+j]!=key[j]) {flag=0;break;} if (flag)return i; }return -1; }3.字符串截取语法:mid(char str[],int start,int len,char strback[]) 参数:str[]:操作的目标字符串start:从第start个字符串开始,截取长度为len的字符ACM常考算法len:从第start个字符串开始,截取长度为len的字符strback[ 截取的到的字符]:返回值:0:超出字符串长度,截取失败;1:截取成功注意:需要string.h源程序:int mid(char str[],int start,int len,char strback[]) {int l,i,k=0; l=strlen(str);if (start+lenl)return 0; for (i=start;istart+len;i++) strback[k++]=str[i]; strback[k]='\0'; return 1; }三、计算几何1.叉乘法求任意多边形面积语法:result=polygonarea(Point *polygon,int N); 参数:*polyg多变形顶点数组on:N:多边形顶点数目返回多边形面积值:注意:源程序:支持任意多边形,凹、凸皆可多边形顶点输入时按顺时针顺序排列typedef struct { double x,y; } Point;double polygonarea(Point *polygon,int N) {int i,j;double area = 0;for (i=0;ii++) { j = (i + 1) % N;area += polygon[i].x * polygon[j].y; area -= polygon[i].y *polygon[j].x; }ACM常考算法area /= 2;return(area 0 ? -area : area); }2.求三角形面积语法:result=area3(float x1,float y1,float x2,float y2,float x3,float y3); 参数:x1~3:三角形3个顶点x坐标y1~3:三角形3个顶点y坐标返回三角形面积值:注意:源程序:需要math.hfloat area3(float x1,float y1,float x2,float y2,float x3,float y3) {float a,b,c,p,s;a=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); b=sqrt((x1-x3)*(x1-x3)+(y1-y3)*(y1-y3)); c=sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)); p=(a+b+c)/2;s=sqrt(p*(p-a)*(p-b)*(p-c)); return s; }3.两矢量间角度语法:result=angle(double x1,double y1,double x2,double y2); 参数:x/y1~两矢量的坐标2:返回两的角度矢量值:注意:源程序:返回角度为弧度制,并且以逆时针方向为正方向需要math.h#define PI 3.__-__double angle(double x1,double y1,double x2,double y2) {ACM常考算法double dtheta,theta1,theta2; theta1 = atan2(y1,x1); theta2 =atan2(y2,x2); dtheta = theta2 - theta1; while (dtheta PI) dtheta -= PI*2; while (dtheta -PI) dtheta += PI*2; return(dtheta); }4.两点距离(2D、3D)语法:result=distance_2d(float x1,float x2,float y1,float y2); 参数:x/y/z1各点的x、y、z坐标~2:返回两点之间的距离值:注意:源程序:需要math.hfloat distance_2d(float x1,float x2,float y1,float y2) {return(sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))); }float distance_3d(float x1,float x2,float y1,float y2,float z1,float z2) { return(sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))); }5.射向法判断点是否在多边形内部语法:result=insidepolygon(Point *polygon,int N,Point p); 参数:*polyg多边形顶点数组on:N:多边形顶点个数p:被判断点返回0:点在多边形内部;1:点在多边形外部值:注意:若p点在多边形顶点或者边上,返回值不确定,需另行判断ACM常考算法源程序:需要math.h#define MIN(x,y) (x y ? x : y)#define MAX(x,y) (x y ? x : y) typedef struct { double x,y; } Point;int insidepolygon(Point *polygon,int N,Point p) {int counter = 0; int i;double xinters; Point p1,p2;p1 = polygon;for (i=1;ii++) { p2 = polygon[i % N];if (p.y MIN(p1.y,p2.y)) {if (p.y = MAX(p1.y,p2.y)) {if (p.x = MAX(p1.x,p2.x)) { if (p1.y != p2.y) { xinters =(p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;if (p1.x == p2.x || p.x = xinters) counter++; } } } }p1 = p2; }if (counter % 2 == 0) return(__); elsereturn(INSIDE); }6.判断点是否在线段上语法:result=Pointonline(Point p1,Point p2,Point p); 参数:p1、p2:线段的两个端点p:被判断点返回0:点在不在线段上;1:点在线段上值:注意:源程若p线段端点上返回1 需要math.hACM常考算法序:#define MIN(x,y) (x y ? x : y)#define MAX(x,y) (x y ? x : y) typedef struct {double x,y; } Point;int FC(double x1,double x2) {if (x1-x20.000002x1-x2-0.000002)return 1;else return 0; }int Pointonline(Point p1,Point p2,Point p) {double x1,y1,x2,y2; x1=p.x-p1.x; x2=p2.x-p1.x; y1=p.y-p1.y; y2=p2.y-p1.y;if (FC(x1*y2-x2*y1,0)==0)return 0;if ((MIN(p1.x,p2.x)=p.xp.x=MAX(p1.x,p2.x))(MIN(p1.y,p2.y)=p.yp.y=MAX(p1.y,p2.y))) return 1;else return 0; }7.判断两线段是否相交语法:result=sectintersect(Point p1,Point p2,Point p3,Point p4); 参数:p1~两条线段的四个端点4:返回0:两线段不相交;1:两线段相交;2两线段首尾相接值:注意:源程序:p1!=p2;p3!=p4;#define MIN(x,y) (x y ? x : y)#define MAX(x,y) (x y ? x : y) typedef struct { double x,y; } Point;int lineintersect(Point p1,Point p2,Point p3,Point p4) {Point tp1,tp2,tp3; if((p1.x==p3.xp1.y==p3.y)||(p1.x==p4.xp1.y==p4.y)||(p2.x==p3.xp2.y==p3.y )||(p2.x==p4.xp2.y==p4.y)) return 2; //快速排斥试验if((MIN(p1.x,p2.x)p3.xp3.xMAX(p1.x,p2.x)MIN(p1.y,p2.y)p3.yMAX(p1.y,p2.y))|| ACM常考算法(MIN(p1.x,p2.x)p4.xp3.xMAX(p1.x,p2.x)MIN(p1.y,p2.y)p3.yMAX(p1.y,p2.y))) ; else return 0;//跨立试验tp1.x=p1.x-p3.x; tp1.y=p1.y-p3.y; tp2.x=p4.x-p3.x; tp2.y=p4.y-p3.y; tp3.x=p2.x-p3.x; tp3.y=p2.y-p3.y;if ((tp1.__tp2.y-tp1.y*tp2.x)*(tp2.__tp3.y-tp2.y*tp3.x)=0)return 1;else return 0; }8.判断线段与直线是否相交语法:result=lineintersect(Point p1,Point p2,Point p3,Point p4); 参数:p1、p2:线段的两个端点p3、p4:直线上的两个点返回0:线段直线不相交;1:线段和直线相交值:注意:源程序:如线段在直线上,返回1typedef struct { double x,y; } Point;int lineintersect(Point p1,Point p2,Point p3,Point p4) {Point tp1,tp2,tp3; tp1.x=p1.x-p3.x; tp1.y=p1.y-p3.y; tp2.x=p4.x-p3.x; tp2.y=p4.y-p3.y; tp3.x=p2.x-p3.x; tp3.y=p2.y-p3.y;if ((tp1.__tp2.y-tp1.y*tp2.x)*(tp2.__tp3.y-tp2.y*tp3.x)=0)return 1;else return 0; }9.点到线段最短距离语法:result=mindistance(Point p1,Point p2,Point q); 参数:p1、线段的两个端点p2:ACM常考算法q:判断点返回点q到线段p1p2的距离值:注意:源程序:需要math.h#define MIN(x,y) (x y ? x : y)#define MAX(x,y) (x y ? x : y) typedef struct { double x,y; } Point;double mindistance(Point p1,Point p2,Point q) {int flag=1; double k; Point s;if (p1.x==p2.x) {s.x=p1.x;s.y=q.y;flag=0;} if (p1.y==p2.y){s.x=q.x;s.y=p1.y;flag=0;} if (flag) {k=(p2.y-p1.y)/(p2.x-p1.x);s.x=(k*k*p1.x+k*(q.y-p1.y)+q.x)/(k*k+1); s.y=k*(s.x-p1.x)+p1.y; }if (MIN(p1.x,p2.x)=s.xs.x=MAX(p1.x,p2.x))return sqrt((q.x-s.x)*(q.x-s.x)+(q.y-s.y)*(q.y-s.y)); elsereturnMIN(sqrt((q.x-p1.x)*(q.x-p1.x)+(q.y-p1.y)*(q.y-p1.y)),sqrt((q.x-p2.x)*(q.x-p2.x)+(q.y-p2.y)*(q.y-p2.y))); }10.求两直线的交点语法:result=mindistance(Point p1,Point p2,Point q); 参数:p1~直线上不相同的两点p4:*p:通过指针返回结果返回1:两直线相交;2:两直线平行值:注意:源程序:如需要判断两线段交点,检验k和对应k1(注释中)的值是否在0~1之间,用在0~1之间的那个求交点ACM常考算法typedef struct { double x,y; } Point;int linecorss(Point p1,Point p2,Point p3,Point p4,Point *p) {double k; //同一直线if ((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x)==0(p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x)==0) return 2; //平行,不同一直线if ((p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y)==0) return 0;k=((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y));//k1=((p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y)); (*p).x=p1.x+k*(p2.x-p1.x);(*p).y=p1.y+k*(p2.y-p1.y); return 1;//有交点}11.判断一个封闭图形是凹集还是凸集语法:result=convex(Point *p,int n); 参数:*p:封闭曲线顶点数组n:封闭曲线顶点个数返回1:凸集;-1:凹集;0:曲线不符合要求无法计算值:注意:源程序:默认曲线为简单曲线:无交叉、无圈typedef struct { double x,y; } Point;。
ACM计算几何
快速排斥试验引申
• 思考: • 简单的改造一下就可以用来判断一个矩形 是否在另一个矩形内部 • NKOJ 1177 rectangles
凸包
• convex hull • 是指对于平面上给定的一些点,选取一个 最小的凸多边形使得这些点或者在其内部, 或者在其边上
求凸包的Graham扫描法
• 对于一个有三个或以上点的点集Q • 令p0为Q中Y-X坐标排序下最小的点 设<p1,p2,...pm>为对其余点按以p0为中心的极角 逆时针排序所得的点集(如果有多个点有相同的 极角,除了距p0最远的点外全部移除) 压p0进栈S,压p1进栈S,压p2进栈S for(i=3;i<=m;++i){ while(由S的栈顶元素的下一个元素、S的栈顶 元素以及pi构成的折线段不拐向左侧){ 对S弹栈 压pi进栈S } } return S
计算几何
需要注意的细节
• 常用头文件#include<math.h> • 计算几何中一般来说使用double型比较频 繁,请注意数据类型的选择,该用实数的 时候就用double,而float容易失去精度。 • 判断double型的x是否为0,应当用x<eps && x>-eps(或者fabs(x)<eps),其中eps 代表某个精度,常常取eps=0.000001,还 有其他类似情况也要注意double类型的精 度问题
需要注意的细节
• 圆周率取3.141592654或者更精确,或者用 acos(-1) • 角度制和弧度制的转换,C/C++中的三角函 数均为弧度制 • 尽量少用除法,开方,三角函数,容易失 去精度。用除法时注意除数不为0
向量及其运算
免费-ACM常用算法计算几何——吴翼-64页文档资料
◦ 一个避免精度问题的加速方法
Authored by Will, IIIS, THU 2020/1/21
8
预备知识:距离与交点的计算
点的距离计算
◦ 线段,直线 ◦ 圆,多边形
线段相关
◦ 线段距离? ◦ 线段的交点?
圆相关
◦ 直线与圆的距离与交点 ◦ 点与圆的切点 ◦ 两圆的公切点
计算方法
◦ 类似Monotone Chain O(NlogN)
更一般的性质与问题
◦ 简单正交多边形的正交凸包 ◦ 口袋的面积 ◦ 最小的周长
Authored by Will, IIIS, THU 2020/1/21
16
凸包上的序——凸性
凸包的定向 直线与凸包 矩形覆盖问题 点与凸包 凸包与凸包 凸包上的动态计算问题 凸包的划分问题
◦ 线段的相交测试 ◦ 面积的计算
右手方向与左手方向
Authored by Will, IIIS, THU 2020/1/21
7
预备知识:另一个例子
判断点在多边形内部
◦ 凸多边形 ◦ 简单多边形
射线法——效率高!
◦ 共线的处理?
随机斜率 纵切变换
转角法——优美!
◦ 精度问题?
浅谈一些几何问题
清华大学 交叉信息院 吴翼 Will
Authored by Will, IIIS, THU 2020/1/21
1
前言:计算几何与计算机科学
机械自动控制 地理信息贪测 计算机辅助设计 模式识别
◦ 人脸识别 ◦ 相关图像处理
游戏领域
◦ 碰撞检测 ◦ 光线追踪 ◦ 三维场景渲染
参加ACM大赛所需的基础知识 (2)
参加ACM比赛所需的基础知识语言是最重要的基本功无论侧重于什么方面,只要是通过计算机程序去最终实现的竞赛,语言都是大家要过的第一道关。
亚洲赛区的比赛支持的语言包括C/C++与JAVA。
笔者首先说说JAVA,众所周知,作为面向对象的王牌语言,JAVA在大型工程的组织与安全性方面有着自己独特的优势,但是对于信息学比赛的具体场合,JAVA则显得不那么合适,它对于输入输出流的操作相比于C++要繁杂很多,更为重要的是JAVA程序的运行速度要比C++慢10倍以上,而竞赛中对于JAVA程序的运行时限却往往得不到同等比例的放宽,这无疑对算法设计提出了更高的要求,是相当不利的。
其实,笔者并不主张大家在这种场合过多地运用面向对象的程序设计思维,因为对于小程序来说这不旦需要花费更多的时间去编写代码,也会降低程序的执行效率。
接着说C和C++。
许多现在参加讲座的同学还在上大一,C的基础知识刚刚学完,还没有接触过C++,其实在赛场上使用纯C的选手还是大有人在的,它们主要是看重了纯C在效率上的优势,所以这部分同学如果时间有限,并不需要急着去学习新的语言,只要提高了自己在算法设计上的造诣,纯C一样能发挥巨大的威力。
而C++相对于C,在输入输出流上的封装大大方便了我们的操作,同时降低了出错的可能性,并且能够很好地实现标准流与文件流的切换,方便了调试的工作。
如果有些同学比较在意这点,可以尝试C和C++的混编,毕竟仅仅学习C++的流操作还是不花什么时间的。
C++的另一个支持来源于标准模版库(STL),库中提供的对于基本数据结构的统一接口操作和基本算法的实现可以缩减我们编写代码的长度,这可以节省一些时间。
但是,与此相对的,使用STL要在效率上做出一些牺牲,对于输入规模很大的题目,有时候必须放弃STL,这意味着我们不能存在“有了STL就可以不去管基本算法的实现”的想法;另外,熟练和恰当地使用STL必须经过一定时间的积累,准确地了解各种操作的时间复杂度,切忌对STL中不熟悉的部分滥用,因为这其中蕴涵着许多初学者不易发现的陷阱。
acm计算几何_讲义
PKU 3304 segments
Output
For each test case, your program must output "Yes!", if a line with desired property exists and must output "No!" otherwise. You must assume that two floating point numbers a and b are equal if |a - b| < 10-8.
PKU 3304 segments
Description
ห้องสมุดไป่ตู้
Given n segments in the two dimensional space, write a program, which determines if there exists a line such that after projecting these segments on it, all projected segments have at least one point in common.
You are to find the length of the shortest path through a chamber containing obstructing walls. The chamber will always have sides at x = 0, x = 10, y = 0, and y = 10. The initial and final points of the path are always (0, 5) and (10, 5). There will also be from 0 to 18 vertical walls inside the chamber, each with two doorways. The figure below illustrates such a chamber and also shows the path of minimal length.
ACM竞赛中的数学方法初步
• 向量a-b和p之间的夹角theta可以比较容易 计算出来(使用内积方法和反三角函数), 用 球半径乘以theta的余角即可以得出所求球 面距离. • 注意特殊情况: 如果AB两点重合, 则整个球 面上的点到AB的距离都是相等的, 那么P点 到AB的距离也是相等的, 所以此时所求的球 面距离为P到自身的距离, 为零. 需要单独处 理
另一种思路
• 可以证明以下事实: 将一个n边形依次以其 每边中点为对称中心做中心对称(反射)变换, n次变换之后, 等价于对此多边形做了一个 以第一个顶点为中心, 180度的旋转变换. • 可以任意选定一个点p, 依次对每个中心做 反射变换, n次之后得到q, 则第一个顶点是 (p+q)/2, 由此可以得到其它顶点
• 已知两点的极坐标
– 其中, 为经度数, 以证明球面距离为
,为纬度数, 则可 Nhomakorabea• 极坐标与直角坐标之间的换算关系:
x R cos cos y R cos sin z R sin
其中, θ是纬度, φ是经度
• 已知极坐标,也可以先用上面的公式计算直角坐标, 然后算球面距离, 但是会有精度损失
BOJ1054 Equidistance
• 给定球面两点A,B的极坐标, 再给定第三点P 的极坐标, 求球面上到A,B两点距离相等的 点(组成一个大圆O1)到P点的最短球面距离 • 首先, 把极坐标转换成直角坐标. 以a,b,p代 表A,B,P对应的向量. • 到A,B距离相等的点集构成一个平面, 法向 量是a-b, 过点(a+b)/2, 圆O1在这个平面上
扇形重心公式
• 如果剩下的pizza的重心不在桌子上, pizza 会掉下来. 剩下的pizza的重心就是所有 pizza片的几何中心(坐标的算术平均值), pizza片的重心可以通过积分手算出来
ACM必做50题的解题-计算几何
ACM必做50题的解题-计算几何.txt生活,是用来经营的,而不是用来计较的。
感情,是用来维系的,而不是用来考验的。
爱人,是用来疼爱的,而不是用来伤害的。
金钱,是用来享受的,而不是用来衡量的。
谎言,是用来击破的,而不是用来装饰的。
信任,是用来沉淀的,而不是用来挑战的。
POJ 1113 WALL计算几何,求凸包这题的结果等于这个多边形构成的凸包的周长加上以所给半径为半径的圆的周长步骤如下:1)算法首先寻找最最靠下方的点,如果遇到y坐标相同,则寻找x坐标最小的点firstP2)然后根据所有点相对于firstP的偏角的大小进行排序,遇到偏角相等的,只取距离firstP最远的点(排序利用自己手写的快排)3)然后利用Graham算法求凸包4)最后直接求职#include <iostream>#include <cmath>#define PI 3.1415926#define MAX_N 1000using namespace std;//存储原始输入的坐标值,rad是输入的半径double cord[MAX_N + 2][2], rad;int seq[MAX_N + 2];int stack[MAX_N + 2];int n, top;int firstP;int realN;void swap(int pos1, int pos2){int temp = seq[pos1];seq[pos1] = seq[pos2];seq[pos2] = temp;}int dir(int nodes, int node1, int node2){double x1 = cord[node1][0], y1 = cord[node1][1];double x2 = cord[node2][0], y2 = cord[node2][1];double sx = cord[nodes][0], sy = cord[nodes][1];return (x2 - sx) * (y1 - sy) - (x1 - sx) * (y2 - sy);}double getDist(int node1, int node2){double x1 = cord[node1][0], y1 = cord[node1][1];double x2 = cord[node2][0], y2 = cord[node2][1];double res = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));return res;}int compare(int node1, int node2){double x1 = cord[node1][0], y1 = cord[node1][1];double x2 = cord[node2][0], y2 = cord[node2][1];double sx = cord[firstP][0], sy = cord[firstP][1];double type = dir(firstP, node1, node2);if(type == 0){double dist1 = (x1 - sx) * (x1 - sx) + (y1 - sy) * (y1 - sy);double dist2 = (x2 - sx) * (x2 - sx) + (y2 - sy) * (y2 - sy);if(dist1 > dist2)return -2;else if(dist1 == dist2)return 0;elsereturn 2;}else if(type > 0)return 1;elsereturn -1;}void fastSort(int start, int end){if(start < end){int curPos = start;int posS = start, posE = end + 1;while(true){while(compare(seq[++posS], seq[curPos]) < 0 && posS < end); while(compare(seq[--posE], seq[curPos]) > 0 && posE > start); if(posS < posE)swap(posS, posE);elsebreak;}swap(curPos, posE);fastSort(start, posE - 1);fastSort(posE + 1, end);}}void sortSeq(){int i, s = 0;for(i = 1; i <= n; i++){//最低最左点不参加排序if(i == firstP)continue;seq[++s] = i;}realN = n - 1;fastSort(1, realN);//清理夹角相同但是距离不同的点,只取举例firstP最远的点i = 1;while(i < realN){s = i + 1;//equal angle but smaller distancewhile(s <= realN && compare(seq[i], seq[s]) == -2) {seq[s] = -1; //置为无效s++;}i = s;}}//寻找凸包void findQ(){int nodes, node1, node2, type;top = 0;stack[top++] = firstP;int s = 1;int c = 0;while(c < 2){if(seq[s] != -1){c++;stack[top++] = seq[s];}s++;}for(; s <= realN; s++){if(seq[s] == -1)continue;while(true){nodes = stack[top - 2];node1 = stack[top - 1];node2 = seq[s];type = dir(nodes, node1, node2);if(type >= 0)top--;elsebreak;}stack[top++] = seq[s];}}double getRes(){double totalDist = 0;int lastNode = firstP;int curNode;while(top > 0){curNode = stack[--top];totalDist += getDist(lastNode, curNode);lastNode = curNode;}//totalDist += getDist(lastNode, firstP);totalDist += 2 * PI * rad;return totalDist;}int main(){int i;cin>>n>>rad;int minX = INT_MAX, minY = INT_MAX;for(i = 1; i <= n; i++){cin>>cord[i][0]>>cord[i][1];if((cord[i][1] < minY) || (cord[i][1] == minY && cord[i][0] < minX)){firstP = i;minX = cord[i][0];minY = cord[i][1];}}sortSeq();findQ();double res = getRes();printf("%.0f\n", res);return 0;}POJ1292 Will Indiana Jones Get There?题目大意:英雄Jones现在在位置1,有人在位置2呼救,所以他要过去救他,但是有个条件,他必须在墙上走,其实就是说他只能在图示的线段上走,但是线段间有空隙,所以要用一个长板搭在线段间才能从一个线段到另外一个线段,问怎么找到一个路径使得要使用的长板最小。
ACM_计算几何类题目
之所以推荐计算几何题,是因为,本人感觉ACM各种算法中计算几何算是比较实际的算法,在很多领域有着重要的用途(例如本人的专业,GIS)。
以后若有机会,我会补充、完善这个列表。
计算几何题的特点与做题要领:1.大部分不会很难,少部分题目思路很巧妙2.做计算几何题目,模板很重要,模板必须高度可靠。
3.要注意代码的组织,因为计算几何的题目很容易上两百行代码,里面大部分是模板。
如果代码一片混乱,那么会严重影响做题正确率。
4.注意精度控制。
5.能用整数的地方尽量用整数,要想到扩大数据的方法(扩大一倍,或扩大sqrt2)。
因为整数不用考虑浮点误差,而且运算比浮点快。
一。
点,线,面,形基本关系,点积叉积的理解POJ 2318 TOYS(推荐)/JudgeOnline/problem?id=2318POJ 2398 Toy Storage(推荐)/JudgeOnline/problem?id=2398一个矩形,有被若干直线分成N个格子,给出一个点的坐标,问你该点位于哪个点中。
知识点:其实就是点在凸四边形内的判断,若利用叉积的性质,可以二分求解。
POJ 3304 Segments/JudgeOnline/problem?id=3304知识点:线段与直线相交,注意枚举时重合点的处理POJ 1269 Intersecting Lines/JudgeOnline/problem?id=1269知识点:直线相交判断,求相交交点POJ 1556 The Doors (推荐)/JudgeOnline/problem?id=1556知识点:简单图论+简单计算几何,先求线段相交,然后再用Dij求最短路。
POJ 2653 Pick-up sticks/JudgeOnline/problem?id=2653知识点:还是线段相交判断POJ 1066 Treasure Hunt/JudgeOnline/problem?id=1066知识点:线段相交判断,不过必须先理解“走最少的门”是怎么一回事。
ACM算法 计算几何基础ppt课件
57 2020/4/15
58 2020/4/15
59 2020/4/15
60 2020/4/15
61 2020/4/15
62 2020/4/15
63 2020/4/15
64 2020/4/15
特别提醒:
以上介绍的线段的三个属性, 是计算几何的基础,在很多方 面都有应用,比如求凸包等等, 请务必掌握!
15 2020/4/15
第二单元
多边形面积 和重心
16 2020/4/15
基本问题(1):
给定一个简单多边形,求其 面积。
输入:多边形(顶点按逆时 针顺序排列)
输出:面积S
17 2020/4/15
A=sigma(Ai) (i=1…N-2)
P1
A1 P2
P6 A4
P5 A3
A2 P4
P3
25 2020/4/15
凹多边形的面积?
P3
P2 P4
P1
26 2020/4/15
依然成立!!!
多边形面积公式:A=sigma(Ai) (i=1…N-2)
结论: “有向面积”A比“面积”S其实更本
质!
27 2020/4/15
思考如下图形:
18 2020/4/15
Any good idea?
19 2020/4/15
先讨论最简单的多边形——三角形
20 2020/4/15
三角形的面积:
在解析几何里, △ABC的面积可以通过 如下方法求得:
点坐标 => 边长 => 海伦公式 => 面积
21 2020/4/15
思考:此方法的缺点:
C=sigma((↑Pi +↑Pi+1)(↑Pi ×↑Pi+1) ) /(6A)