#include "stdafx.h" #include <stdio.h> #include <windows.h> #include <stdlib.h> #include <math.h> 坐标数据结构: typedef struct { float x; float y; }Point; typedef bool(*Func)(Point, Point, Point); 判断点test是否在a,b组成的直线的上方: bool Upstair(Point a, Point b, Point test) { double k, d; if (fabs(a.x - test.x) < 0.000001 && fabs(a.y - test.y) < 0.000001 || fabs(b.x - test.x) < 0.000001 && fabs(b.y - test.y) < 0.000001) return false; /* 此时test点肯定不符合结果(联想在main函数寻找a,b点时的要求) */ if (fabs(b.x - a.x) < 0.000001) return false; k = (b.y - a.y) / (b.x - a.x); d = a.y - k * a.x; double ret = k*test.x - test.y + d; if (ret < -0.000001) //点在上方 return true; else //点在线上 和 点在线的下方 return false; } 判断点test是否在a,b组成的直线的下方: bool Downstair(Point a, Point b, Point test) { double k, d; if (fabs(a.x - test.x) < 0.000001 && fabs(a.y - test.y) < 0.000001 || fabs(b.x - test.x) < 0.000001 && fabs(b.y - test.y) < 0.000001) return false; /* 此时test点肯定不符合结果(联想在main函数寻找a,b点时的要求) */ if (fabs(b.x - a.x) < 0.000001) return false; k = (b.y - a.y) / (b.x - a.x); d = a.y - k * a.x; double ret = k*test.x - test.y + d; if (ret > 0.000001) //点在下方 return true; else //点在线上 和 点在线的上方 return false; } 查找符合的点,递归函数: void FindPoint(Point point[], int plen, Point a, Point b, Func func) { if (plen == 0) return; /* 找出 Pmax 点 */ Point pmax; pmax.x = point[0].x; pmax.y = point[0].y; double k, d; k = (b.y - a.y) / (b.x - a.x); d = a.y - k * a.x; double dist = fabs(k*pmax.x - pmax.y + d); double newdist; for (int i = 1; i < plen; ++i) { newdist = fabs(k*point[i].x - point[i].y + d); if (newdist - dist > 0.000001) { pmax.x = point[i].x; pmax.y = point[i].y; } else if (fabs(newdist - dist) < 0.000001) { //选择使角PmaxPaPb最大的点 double k_pmax = (pmax.y - a.y) / (pmax.x - a.x); double k_point = (point[i].y - a.y) / (point[i].x - a.x); if (fabs(k_point - k) - fabs(k_pmax - k) > 0.000001) { pmax.x = point[i].x; pmax.y = point[i].y; } } } printf("Point(%f, %f)\n", pmax.x, pmax.y); /* 找出各自符合满足 Pmax,Pa 和 Pmax,Pb 的点 */ Point *p1 = (Point *)malloc((plen / 2 + 1)*sizeof(Point)); Point *p2 = (Point *)malloc((plen / 2 + 1)*sizeof(Point)); int p1idx = 0, p2idx = 0; for (int i = 0; i < plen; ++i) { if (func(pmax, a, point[i])) { p1[p1idx].x = point[i].x; p1[p1idx].y = point[i].y; p1idx++; } else if (func(pmax, b, point[i])) { p2[p2idx].x = point[i].x; p2[p2idx].y = point[i].y; p2idx++; } } /* 递归寻找Pmax */ FindPoint(p1, p1idx, pmax, a, func); FindPoint(p2, p2idx, pmax, b, func); free(p1); free(p2); }主函数: int _tmain(int argc, _TCHAR* argv[]) { int number = 0; while (number < 3) { printf("How much Point do you input(>=3):\n"); scanf("%d", &number); } printf("Please input Point:\n"); Point *p = (Point *)malloc(number * sizeof(Point)); for (int i = 0; i < number; ++i) { scanf("%f%f", &(p[i].x), &(p[i].y)); } /* 找出两个顶点 */ Point a, b; a.x = p[0].x; a.y = p[0].y; b.x = p[0].x; b.y = p[0].y; for (int i = 1; i < number; ++i) { if (a.x - p[i].x > 0.000001) //有比a更小的(横坐标) { a.x = p[i].x; a.y = p[i].y; } else if (fabs(a.x - p[i].x) < 0.000001) { // 存在和a在同一竖直线上的点,此时应该选择最上或最下的点(这里选最上) if (p[i].y - a.y > 0.000001) { a.x = p[i].x; a.y = p[i].y; } } if (b.x - p[i].x < -0.000001) { printf("b change\n"); b.x = p[i].x; b.y = p[i].y; } else if (fabs(b.x - p[i].x) < 0.000001) { // 存在和b在同一竖直线上的点,此时应该选择最上或最下的点(这里选最下,和a对应,为了更可能的均分上包和下包点数) if (p[i].y - a.y < -0.000001) { b.x = p[i].x; b.y = p[i].y; } } } /* 所有点在一条竖直的线,则此时已是所求结果 */ if (fabs(a.x - b.x) < 0.000001) { printf("Point(%f, %f)\n", a.x, a.y); printf("Point(%f, %f)\n", b.x, b.y); system("pause"); return 0; } printf("Point(%f, %f)\n", a.x, a.y); printf("Point(%f, %f)\n", b.x, b.y); /* 划分点为两个集,即上包 和 下包*/ Point *p1 = (Point *)malloc((number / 2 + 1)*sizeof(Point)); Point *p2 = (Point *)malloc((number / 2 + 1)*sizeof(Point)); int p1idx = 0, p2idx = 0; for (int i = 0; i < number; ++i) { if (Upstair(a, b, p[i])) { p1[p1idx].x = p[i].x; p1[p1idx].y = p[i].y; p1idx++; } else if (Downstair(a, b, p[i])) { p2[p2idx].x = p[i].x; p2[p2idx].y = p[i].y; p2idx++; } } FindPoint(p1, p1idx, a, b, Upstair); FindPoint(p2, p2idx, a, b, Downstair); free(p); free(p1); free(p2); system("pause"); _tmain(0, NULL); return 0;
算法分析:
在输入数中分上包和下包时时间复杂度为O(n),两个递归函数的调用规模下降为n/2.
故可得T(n) = 2T(n/2) + n,递归函数遍历元素时间复杂度为n,然后同样道理递归, 最好的效率是刚好上包和下包元素相等或差一的情况。
由T(n) = 2T(n/2) + n ,得T(2^k) = 2T(2^k-1) + 2^k
T(2^k) = 2(2T(2^k-2) + 2^k-1) + 2^k
= 2^2T(2^k-2) + 2*2^k
= 2^kT(1) + k*2^k
由T(1) = 1,k = logn
T(n) = n + logn*n
所以,时间复杂度是nlogn.