首页 > 代码库 > UVA 12386 Smallest Polygon n个点的任意多边形求最小周长 科学的暴力

UVA 12386 Smallest Polygon n个点的任意多边形求最小周长 科学的暴力

题目链接:

题意:

给定n个点,用n个点组成的多边形中(可以是凹多边形,但n个点一定要全在多边形上)

在所有能由n个点构成的多边形中

求最小面积的多边形的周长 - 最小周长。

思路:

首先我们选择一个定点,则接下来的数进行一个排列,有(n-1)!个排列。

这个序列相邻两个数之间有一条线段。

判断多边形合法:任意两条线段不相交即可。n^2

剩下就是简单的更新答案了。

所以复杂度是 ( n-1 ) ! * n*n

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <cmath>

using namespace std;

const int MAX_N = 2507;

struct point {
    double x, y;
    point(double _x = 0, double _y = 0) {
        x = _x, y = _y;
    }
    bool operator < (const point &rhs) const {
        if (x != rhs.x) return x < rhs.x;
        return y < rhs.y;
    }
};

int n;
int top;
point st[100], p[100];

typedef point Point;

double cross(point p0, point p1, point p2) {
    return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

double mult_cross(Point p1, Point p2, Point p0) {
	return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x);
}

bool is_cross(Point p1, Point p2, Point p3, Point p4) {
	if (std::min(p1.x, p2.x) <= std::max(p3.x, p4.x) &&
	    std::min(p3.x, p4.x) <= std::max(p1.x, p2.x) &&
		std::min(p1.y, p2.y) <= std::max(p3.y, p4.y) &&
		std::min(p3.y, p4.y) <= std::max(p1.y, p2.y) &&
		mult_cross(p1, p4, p3) * mult_cross(p2, p4, p3) <= 0 &&
		mult_cross(p3, p2, p1) * mult_cross(p4, p2, p1) <= 0)
		return true;
		return false;
}

double dis(point p1, point p2) {
    return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

int b[100];

bool check() {
    b[n - 1] = n - 1;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (i == j) continue;
            int x = (i + 1) % n, y = (j + 1) % n;
            if (i == y || j == x || x == y) continue;
            if (is_cross(p[b[i]], p[b[x]], p[b[j]], p[b[y]]))
                return false;
        }
    }
    return true;
}

inline double Cross(const Point &a, const Point &b) {
	return a.x * b.y - a.y * b.x;
}

bool Equal(double a, double b) {
	return fabs(a - b) < 1e-6;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T-- > 0) {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i) {
            int x, y;
            scanf("%d%d", &x, &y);
            p[i].x = 1. * x, p[i].y = 1. * y;
        }
        if (n == 3) {
            puts("0.0000");
            continue;
        }
        for (int i = 0; i < n - 1; ++i) b[i] = i;
        double minlength = -1, minarea = -1, minarealength = -1;
        do {
            if (check()) {
                double area = 0, length = 0;
                b[n] = b[0];
                for (int i = 0; i < n; i++) {
                    length += dis(p[b[i]], p[b[i+1]]);
                    area += Cross(p[b[i]], p[b[i+1]]);
                }

                area = fabs(area) * 0.5;
              //  printf("www %.4f %.4f\n", area, length);
               // for (int i = 0; i < n; ++i) printf("(%d %.f %.f) ", b[i], p[b[i]].x, p[b[i]].y); puts("");
                if (minlength == -1) {
                    minlength = length;
                    minarea = area;
                    minarealength = length;
                } else {
                    minlength = min(minlength, length);
                    if (minarea > area || (Equal(area, minarea) && length < minarealength)) {
                        minarea = area;
                        minarealength = length;
                    }
                }
            }
           // for (int i = 0; i < n; ++i) printf("%d ", b[i]);
        } while (next_permutation(b, b + n - 1));
      //  printf("%.4f %.4f %.4f\n", minlength, minarealength, minarea);
        printf("%.4f\n", fabs(minarealength - minlength));
    }
    return 0;
}


UVA 12386 Smallest Polygon n个点的任意多边形求最小周长 科学的暴力