首页 > 代码库 > uva 1331 - Minimax Triangulation(dp)

uva 1331 - Minimax Triangulation(dp)

题目链接:uva 1331 - Minimax Triangulation


题目大意:按照顺时针或者逆时针的顺序给出多边的点,要将这个多边形分解成n-2个三角形,要求使得这些三角行中面积最大的三角形面积尽量小,求最小值。


解题思路:状态很好想,dp[i][j]表示从第i个点到第j个点,划分成j-i-1个三角形的最优解,然后每次转移时,枚举长度和左边界始点,那么根据长度和左边界点就可以知道右边界点,然后枚举左边界和右边界中间的点k,dp[i][j] = min(dp[i][j], max(max(dp[i][k], dp[k][j]), Area(i, k, j)).但是有一个问题,即i,k,j三点围成的三角形是否符合要求,判断的条件即为是否存在除i,k,j三点外的一点位于三角形中,有面积法判断。


然后其实我还一直纠结说凹多边形的时候怎么处理掉得,如图


BCD的组成的三角形式合法的,但是后来想了想,虽然BCD组成的三角形是合法的,但是不会影响到最后的答案。

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

using namespace std;
const int N = 100;
const double INF = 0x3f3f3f3f3f3f;
const double eps = 1e-9;

struct point {
	double x, y;
	void get() {
		scanf("%lf%lf", &x, &y);
	}
}p[N];

int n;
double dp[N][N];

double area (point a, point b, point c) {
	return fabs((b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y))/2;
}

bool judge (int a, int b, int c) {
	double cur = area(p[a], p[b], p[c]);
	for (int i = 0; i < n; i++) {
		if (i == a || i == b || i == c)
			continue;
		double tmp = area(p[a], p[b], p[i]) + area(p[b], p[c], p[i]) + area(p[c], p[a], p[i]);
		if (fabs(tmp - cur) < eps)
			return false;
	}
	return true;
}

double solve () {
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < n; j++)
			dp[j][(j+i)%n] = 0;
	}

	for (int i = 0; i < n; i++)
		dp[i][(i+2)%n] = area(p[i], p[(i+1)%n], p[(i+2)%n]);

	for (int k = 3; k < n; k++) {

		for (int i = 0; i < n; i++) {
			int t = (i + k) % n;
			dp[i][t] = INF;
			for (int j = (i+1)%n; j != t; j = (j+1)%n) {
				if (judge(i, t, j))
					dp[i][t] = min(dp[i][t], max(max(dp[i][j], dp[j][t]), area(p[i], p[j], p[t])));
			}
		}
	}

	double ans = INF;
	for (int i = 0; i < n; i++)
		ans = min (ans, dp[i][(i+n-1)%n]);
	return ans;
}

int main () {
	int cas;
	scanf("%d", &cas);
	while (cas--) {
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
			p[i].get();

		printf("%.1lf\n", solve());
	}
	return 0;
}