网上很多区间dp的代码是记忆化搜索的,还有些说这种区间dp必须倒序枚举
其实没有必要倒序,我们只需要按正常的区间dp的定义,第一维是长度,第二维枚举起点,第三维枚举断点即可
判断凸包的方法就是跟网上一样的常用方法Graham
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1005; const int inf = 1000000000; struct node { int x, y; } p[maxn], save[maxn], tmp[maxn]; int cost[maxn][maxn], n, m; int dp[maxn][maxn]; int dis(node p1, node p2, node p0) { return (p1.x-p0.x) * (p2.y-p0.y) - (p2.x-p0.x) * (p1.y-p0.y); } bool cmp(const node &a, const node &b) { if (a.y == b.y) return a.x < b.x; return a.y < b.y; } int Graham(node *p,int n) { sort(p,p + n,cmp); save[0] = p[0]; save[1] = p[1]; int top = 1; for (int i = 0;i < n; i++) { while (top && dis(save[top],p[i],save[top-1]) >= 0) top--; save[++top] = p[i]; } int mid = top; for(int i = n - 2; i >= 0; i--) { while (top > mid && dis(save[top],p[i],save[top-1])>=0) top--; save[++top]=p[i]; } return top; } int Count(node a, node b) { return (abs(a.x+b.x) * abs(a.y+b.y)) % m; } int main() { while (scanf("%d%d",&n,&m) != EOF) { for (int i = 0; i < n; ++i) scanf("%d%d",&p[i].x,&p[i].y); int tot = Graham(p,n); //求凸包 if (tot != n) printf("I can't cut.\n"); else { memset(cost,0,sizeof(cost)); for (int i = 0; i < n; ++i) for (int j = i + 2; j < n; ++j) cost[i][j] = cost[j][i] =(abs(save[i].x+save[j].x) * abs(save[i].y+save[j].y)) % m; memset(dp,0x3f,sizeof dp); for(int i=0;i<n;i++) dp[i][i+1]=0; int len,l,r,k; for(len=3;len<=n;len++){ for(l=0;l+len-1<n;l++){ r=l+len-1; for(k=l+1;k<r;k++){ dp[l][r]=min(dp[l][r],dp[l][k]+dp[k][r]+cost[l][k]+cost[k][r]); } } } printf("%d\n",dp[0][n-1]); } } return 0; }View Code