ZOJ3537 Cake(区间dp+凸包判断)

为君一笑 提交于 2020-02-20 13:30:13

网上很多区间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

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!