网上很多区间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;
}
来源:https://www.cnblogs.com/ctyakwf/p/12335231.html
