UVALive 2221 Frontier(计算几何 + DP)
2013-09-24 23:47
381 查看
题目大意:有n个tower,m个monument,要求n个点中找出几个点围成一个凸多边形包含这m个点,使这个多边形周长最小,输出这个周长。
思路:m个点全都要被包含,明显只关系到最外围的点,那么把m个点求凸包,然后考虑如果取某个点为起点顺时针走,那么一个一个点加进去,最后这个点可以和前面的点连接,设中间这个点是k,然后d[ i ][ j ] = min(d[ i ][ k ] + len(k , j) ),其中k、j这段中m没有点在外面,d[ i ][ j ]表示以 i 为起点,j 为终点顺时针走的最短距离。
先开始一直有个地方不会,就是怎么判断这个线没有点在外面,后来发现,只要做三个点叉积就行了,右手比划一下就行了。
这里还有个坑,那就是如果m == 0,那么需要特判,面积不为0,那么此时是个三角形,有可能出现三个点共线的情况,如果 m 有值,就肯定不会取到三角形三点共线的情况。(看 discuss 看来的。。。 = =)
代码如下:
思路:m个点全都要被包含,明显只关系到最外围的点,那么把m个点求凸包,然后考虑如果取某个点为起点顺时针走,那么一个一个点加进去,最后这个点可以和前面的点连接,设中间这个点是k,然后d[ i ][ j ] = min(d[ i ][ k ] + len(k , j) ),其中k、j这段中m没有点在外面,d[ i ][ j ]表示以 i 为起点,j 为终点顺时针走的最短距离。
先开始一直有个地方不会,就是怎么判断这个线没有点在外面,后来发现,只要做三个点叉积就行了,右手比划一下就行了。
这里还有个坑,那就是如果m == 0,那么需要特判,面积不为0,那么此时是个三角形,有可能出现三个点共线的情况,如果 m 有值,就肯定不会取到三角形三点共线的情况。(看 discuss 看来的。。。 = =)
代码如下:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const double INF = 1e9; const double eps = 1e-8; struct Point { double x, y; Point(){} Point(double a,double b): x(a),y(b) {} void read() { scanf("%lf%lf",&x,&y); } Point operator - (const Point& t) const { Point tmp; tmp.x = x - t.x; tmp.y = y - t.y; return tmp; } Point operator + (const Point& t) const { Point tmp; tmp.x = x + t.x; tmp.y = y + t.y; return tmp; } bool operator == (const Point& t) const { return fabs(x-t.x) < eps && fabs(y-t.y) < eps; } }tow[55],mon[1111<<1]; inline double Cross(Point a, Point b, Point c) { // 叉积 return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y); } inline double PPdis(Point a, Point b) { // 点点距离 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } inline double PLdis(Point p,Point l1,Point l2){ // 点线距离 return fabs(Cross(p,l1,l2))/PPdis(l1,l2); } inline bool same_dir(Point a, Point b) { // 向量是否同向 return fabs(a.x*b.y-b.x*a.y) < eps && a.x*b.x > -eps && a.y*b.y > -eps; } bool dotOnSeg(Point p, Point s, Point e) { // 点是否在线段上 if ( p == s || p == e ) // 看具体情况端点是否合法 return true; return fabs((p-s).x*(p-e).y - (p-e).y*(p-s).x) < eps && (p.x-s.x)*(p.x-e.x)<eps && (p.y-s.y)*(p.y-e.y)<eps; } bool Intersect(Point p1, Point p2, Point p3, Point p4, Point& p) { // 直线相交 double a1, b1, c1, a2, b2, c2, d; a1 = p1.y - p2.y; b1 = p2.x - p1.x; c1 = p1.x*p2.y - p2.x*p1.y; a2 = p3.y - p4.y; b2 = p4.x - p3.x; c2 = p3.x*p4.y - p4.x*p3.y; d = a1*b2 - a2*b1; if ( fabs(d) < eps ) return false; p.x = (-c1*b2 + c2*b1) / d; p.y = (-a1*c2 + a2*c1) / d; return true; } bool cmpyx(Point a, Point b) { if ( a.y != b.y ) return a.y < b.y; return a.x < b.x; } void Grahamxy(Point *p, int &n) { // 水平序(住:两倍空间) if ( n < 3 ) return; int i, m=0, top=1; sort(p, p+n, cmpyx); for (i=n; i < 2*n-1; i++) p[i] = p[2*n-2-i]; for (i=2; i < 2*n-1; i++) { while ( top > m && Cross(p[top], p[i], p[top-1]) < eps ) top--; p[++top] = p[i]; if ( i == n-1 ) m = top; } n = top; } bool is[55][55]; double d[55][55]; int main() { int n,m; while(~scanf("%d%d",&n,&m)) { for(int i = 0;i<n;i++) tow[i].read(); for(int i = 0;i<m;i++) mon[i].read(); double ans = INF; if(m == 0) { for(int i = 0;i<n;i++) for(int j = i+1;j<n;j++) for(int k = j+1;k<n;k++) { double tmp = Cross(tow[i],tow[j],tow[k]); if(tmp <= eps && tmp >= -eps) continue; ans = min(ans,PPdis(tow[i],tow[j]) + PPdis(tow[i],tow[k]) + PPdis(tow[j],tow[k])); //printf("i = %d,j = %d,k = %d,ans = %f\n",i,j,k,ans); } printf("%.2f\n",ans); continue; } int tot = m; Grahamxy(mon,tot); //printf("tot = %d\n",tot); //for(int i = 0;i<tot;i++) //printf("x = %f,y = %f\n",mon[i].x,mon[i].y); for(int i = 0;i<n;i++) for(int j = 0;j<n;j++) is[i][j] = 1; for(int i = 0;i<n;i++) { for(int j = 0;j<n;j++) { if(i == j) continue; int ok = 1; for(int k = 0;k<tot;k++) { if(Cross(tow[i],tow[j],mon[k]) >= 0) { ok = 0; break; } } if(!ok) is[i][j] = 0; } is[i][i] = 0; } for(int i = 0;i<n;i++) for(int j = 0;j<n;j++) d[i][j] = INF; for(int i = 0;i<n;i++) for(int j = (i+1)%n;j!=i;j = (j+1)%n) if(is[i][j]) d[i][j] = PPdis(tow[i],tow[j]); for(int begin = 0;begin < n;begin ++) { for(int end = (begin + 1)%n;;end = (end+1)%n) { for(int k = (begin + 1)%n; ;k = (k+1)%n) { if(is[k][end]) d[begin][end] = min(d[begin][end],d[begin][k] + d[k][end]); if(k == end) break; } //printf("begin = %d,end = %d,dd = %f\n",begin,end,d[begin][end]); if(begin == end) break; } } for(int i =0;i<n;i++) ans = min(ans,d[i][i]); printf("%.2f\n",ans); } return 0; } /* 4 0 0 0 0 3 3 0 2 0 */
相关文章推荐
- OpenJMS程序实现消息的发送和接收
- 液晶操作
- 直接插入排序
- 队列-循环队列/链队列
- 数据挖掘十大经典算法
- FTPClient上传 中文目录、中文文件名乱码问题
- 使用java连接hive,并执行hive语句详解
- 寻找4位吸血鬼数字 java
- 使用java连接hive,并执行hive语句详解
- 程序员为什么要写if else,为什么要和别人不一样
- Ubuntu 开启ssh
- 创建单链表的4种方式
- github backup
- 求数组的子数组之和的最大值
- zoj 3366 Light Bulb 三分
- ID(dfs+bfs)-hdu-4127-Flood-it!
- 黑马程序员_日记04(java基础加强01)
- POJ 1118 Lining Up
- zoj 3366 Light Bulb 三分
- zoj 3366 Light Bulb 三分