ZOJ 3537 Cake
区间DP。
首先求凸包判断是否为凸多边形。
如果是凸多边形:假设现在要切割连续的一段点,最外面两个一定是要切一刀的,内部怎么切达到最优解就是求子区间最优解,因此可以区间DP。
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 1000; const int INF = 0x7FFFFFFF; struct point { int x, y; }; point List[MAXN]; point a[MAXN]; int dp[MAXN][MAXN]; int Stack[MAXN], top; int n, p; int tot; int cross(point p0, point p1, point p2) { return (p1.x - p0.x)*(p2.y - p0.y) - (p1.y - p0.y)*(p2.x - p0.x); } double dis(point p1, point p2) { return sqrt((double)(p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y)); } bool cmp(point p1, point p2) { int tmp = cross(List[0], p1, p2); if (tmp>0) return true; else if (tmp == 0 && dis(List[0], p1)<dis(List[0], p2)) return true; else return false; } void init() { int i, k; point p0; scanf("%d%d", &List[0].x, &List[0].y); p0.x = List[0].x; p0.y = List[0].y; k = 0; for (i = 1; i<n; i++) { scanf("%d%d", &List[i].x, &List[i].y); if ((p0.y>List[i].y) || ((p0.y == List[i].y) && (p0.x>List[i].x))) { p0.x = List[i].x; p0.y = List[i].y; k = i; } } List[k] = List[0]; List[0] = p0; sort(List + 1, List + n, cmp); } void graham() { int i; if (n == 1) { top = 0; Stack[0] = 0; } if (n == 2) { top = 1; Stack[0] = 0; Stack[1] = 1; } if (n>2) { for (i = 0; i <= 1; i++) Stack[i] = i; top = 1; for (i = 2; i<n; i++) { while (top>0 && cross(List[Stack[top - 1]], List[Stack[top]], List[i]) <= 0) top--; top++; Stack[top] = i; } } } int cost(int i, int j) { return (abs(a[i].x + a[j].x)*abs(a[i].y + a[j].y)) % p; } void work() { int tmp = top + 1; tot = 0; if (tmp != n) printf("I can't cut.\n"); else { while (top != -1) a[tot++] = List[Stack[top--]]; for (int r = 0, i = tot; r<tot - 1; r++, i++) a[i] = a[i - tot]; tot = 2 * tot - 1; for (int i = 0; i < tot; i++) for (int j = 0; j < tot; j++) dp[i][j] = INF; for (int i = 0; i < tot; i++) { int st = i, en = st + 2 - 1; dp[st][en] = 0; } for (int i = 3; i<tmp; i++) { for (int j = 0; j<tot; j++) { int st = j, en = st + i - 1; if (en >= tot) continue; for (int k = st + 1; k <= en - 1; k++) dp[st][en] = min(dp[st][en], dp[st][k] + dp[k][en] + cost(st, en)); } } int ans = INF; for (int i = 0; i<tot; i++) { int st = i, en = st + tmp - 1 - 1; if (en>=tot) continue; ans = min(ans, dp[st][en]); } printf("%d\n", ans); } } int main() { while (~scanf("%d%d", &n, &p)) { init(); graham(); work(); } return 0; }