POJ 1113 凸包2 Graham-scan 入门题(极角序,水平序)
题意:
国王想建一个周长最短的城墙,使墙的任意一点到城墙的距离都 > l。求这面墙的周长。
不难发现题目要求的就是 凸包的周长+半径为l圆的周长。
不清楚Graham-scan算法的两种排序概念的可以去看看lrj的黑书,黑书介绍了两种排序方法来实现Graham-scan算法。
1. 极角序 (看了lrj的黑书就知道这个排序不能解决某些共线问题,有一定的缺陷,但这题反映不出它的缺陷)
View Code
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> using namespace std; #define eps 1e-8 #define inf 1<<29 const double pi = acos(-1.0); struct point { int x, y; }p[1002], stack[1002]; int det(int x1, int y1, int x2, int y2) { return x1 * y2 - x2 * y1; } int cross(point o, point a, point b) { return det(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y); } double f(int x) { return x * x * 1.0; } double dis(point a, point b) { return sqrt( f(a.x - b.x) + f(a.y - b.y) ); } bool cmp(point a, point b) //极角排序 { int tmp = cross(p[0], a, b); if(tmp > 0 || ( tmp == 0 && dis(p[0], a) < dis(p[0], b) ) ) return 1; return 0; } int n; int l; int main() { int i, j; while( ~scanf("%d%d", &n, &l) ) { for(i = 0; i < n; i++) { scanf("%d%d", &p[i].x, &p[i].y); if(p[i].y < p[0].y || (p[i].y == p[0].y && p[i].x < p[0].x)) swap(p[i], p[0]); //使0变为起始点 } sort(p + 1, p + n, cmp); int top = 0; for(i = 0; i < n; i++) { while(top >= 2 && cross(stack[top-2], stack[top-1], p[i]) < 0) top--; stack[top++] = p[i]; } double ans = pi * 2.0 * l; stack[top++] = stack[0]; //把起始点再次加入,形成一个环,方便以下的计算 for(i = 0; i < top - 1; i++) ans += dis(stack[i], stack[i+1]); printf("%d\n", (int) (ans + 0.5)); } }
2.水平序
View Code
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; #define eps 1e-8 #define inf 1<<29 const double pi = acos(-1.0); struct point { int x, y; }p[1002], stack[1002]; int det(int x1, int y1, int x2, int y2) { return x1 * y2 - x2 * y1; } int cross(point o, point a, point b) { return det(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y); } double f(int x) { return x * x * 1.0; } double dis(point a, point b) { return sqrt( f(a.x - b.x) + f(a.y - b.y) ); } bool cmp(point a, point b) //水平排序 { if(a.y == b.y) return a.x < b.x; return a.y < b.y; } int n, l; int main() { int i, j; while( ~scanf("%d%d", &n, &l) ) { for(i = 0; i < n; i++) scanf("%d%d", &p[i].x, &p[i].y); sort(p, p + n, cmp); int top = 0; for(i = 0; i < n; i++) { while(top >= 2 && cross(stack[top-2], stack[top-1], p[i]) < 0 ) top --; stack[top++] = p[i]; } int t = top + 1; for(i = n - 2; i >= 0; i--) { while(top >= t && cross(stack[top-2], stack[top-1], p[i]) < 0) top--; stack[top++] = p[i]; } double ans = l* 2 * pi; for(i = 0; i < top - 1; i++) ans += dis(stack[i], stack[i+1]); printf("%d\n", (int) (ans + 0.5) ); } return 0; }
水平序Graham-scan写成函数
View Code
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; #define eps 1e-8 #define inf 1<<29 const double pi = acos(-1.0); struct point { int x, y; }p[1002], conbag[1002]; int det(int x1, int y1, int x2, int y2) { return x1 * y2 - x2 * y1; } int cross(point o, point a, point b) { return det(a.x - o.x, a.y - o.y, b.x - o.x, b.y - o.y); } double f(int x) { return x * x * 1.0; } double dis(point a, point b) { return sqrt( f(a.x - b.x) + f(a.y - b.y) ); } bool cmp(point a, point b) { if(a.y == b.y) return a.x < b.x; return a.y < b.y; } int n, l; double graham(point p[], int n) { //if(n < 3) return; int i; sort(p, p + n, cmp); int top = 0; point res[1003]; for(i = 0; i < n; i++) { while(top >= 2 && cross(res[top-2], res[top-1], p[i]) < 0) top--; res[top++] = p[i]; } int t = top + 1; for(i = n - 2; i >= 0; i--) { while(top >= t && cross(res[top-2], res[top-1], p[i]) < 0) top--; res[top++] = p[i]; } res[top++] = p[0]; double ans = 0; for(i = 0; i < top - 1; i++) ans += dis(res[i], res[i+1]); return ans; } int main() { int i, j; while( ~scanf("%d%d", &n, &l) ) { for(i = 0; i < n; i++) scanf("%d%d", &p[i].x, &p[i].y); double ans = graham(p, n) + 2 * pi * l; printf("%d\n", (int) (ans + 0.5) ); } return 0; }


浙公网安备 33010602011771号