*ZOJ3537.Cake(区间DP+凸包多边形判断)

题目链接:https://zoj.pintia.cn/problemsets/91827364500/problems/91827368971
题意:将一个多边形分成多个三角形,求最小代价
解题思路:
参考
首先是凸包的判断
Andrew算法:

struct Point{
    int x,y;
    Point(){}
    Point(int xx,int yy):x(xx),y(yy){}
    void read(){
        scanf("%d%d",&x,&y);
    }
    bool operator < (const Point &other)const{
        if(x == other.x)
            return y < other.y;
        return x < other.x;
    }
    Point operator - (const Point &other)const{
        return Point(x - other.x,y - other.y);
    }
};
Point p[400],ch[400];
int n;
double Cross(Point A,Point B){
    return A.x * B.y - A.y * B.x;
}
//当返回的值小于n时,说明该多边形非凸包
int ConvexHull(){
    sort(p,p+n);
    int cnt = 0;
    for(int i = 0; i < n; i++){
        while(cnt > 1 && Cross(ch[cnt-1] - ch[cnt-2],p[i] - ch[cnt-2]) <= 0) cnt--;
        ch[cnt++] = p[i];
    }
    int k = cnt;
    for(int i = n-2; i >= 0; i--){
        while(cnt > k && Cross(ch[cnt-1] - ch[cnt-2],p[i] - ch[cnt-2]) <= 0) cnt--;
        ch[cnt++] = p[i];
    }
    if(n > 1) cnt--;
    return cnt;
}

DP部分:
使用区间DP,dp[i][j]表示从顶点i到顶点j围成的多边形切割成三角形所需要的最小代价。
那么转移方程就是
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost(i,k)+cost(k,j));
其中k为i到j之间的顶点
同时要注意初始化时候的细节问题

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<algorithm>
#include<math.h>

using namespace std;
const int INF = 0x3f3f3f3f;
int n, mod;
struct Point {
    int x, y;
    Point() {}
    Point(int xx, int yy) :x(xx), y(yy) {}
    void read() {
        scanf("%d%d", &x, &y);
    }
    bool operator < (const Point& other)const {
        if (x == other.x)
            return y < other.y;
        return x < other.x;
    }
    Point operator - (const Point& other)const {
        return Point(x - other.x, y - other.y);
    }
};
Point p[400], ch[400];
int f[400][400];
int dp[400][400];
int calc(Point a, Point b) {
    return (abs(a.x + b.x) * abs(a.y + b.y)) % mod;
}
double Cross(Point A, Point B) {
    return A.x * B.y - A.y * B.x;
}
int ConvexHull() {
    sort(p, p + n);
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        while (cnt > 1 && Cross(ch[cnt - 1] - ch[cnt - 2], p[i] - ch[cnt - 2]) <= 0) cnt--;
        ch[cnt++] = p[i];
    }
    int k = cnt;
    for (int i = n - 2; i >= 0; i--) {
        while (cnt > k && Cross(ch[cnt - 1] - ch[cnt - 2], p[i] - ch[cnt - 2]) <= 0) cnt--;
        ch[cnt++] = p[i];
    }
    if (n > 1) cnt--;
    return cnt;
}
int main() {
    while (scanf("%d%d", &n, &mod) != EOF) {
        memset(f, 0, sizeof(f));
        memset(p, 0, sizeof(p));
        memset(ch, 0, sizeof(ch));
        for (int i = 0; i < n; i++) {
            p[i].read();
        }
        if (n == 3) {
            cout << 0 << endl;
            continue;
        }
        if (ConvexHull() < n) {
            cout << "I can't cut." << endl;
            continue;
        }
        //计算两点间代价
        for (int i = 0; i < n; i++) {
            for (int j = i + 2; j < n; j++) {
                f[i][j] = f[j][i] = calc(ch[i], ch[j]);
            }
        }
        //初始化dp 相邻置为0 其他置为INF
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                dp[i][j]  = INF;
            }
            dp[i][(i + 1) % n] = 0;
        }
        //处理顶点i到j围成的多边形分割成三角形的最小代价
        for (int i = n - 3; i >= 0; i--) {
            for (int j = i + 2; j < n; j++) {
                for (int k = i + 1; k < j; k++) {
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + f[i][k] + f[k][j]);
                }
            }
        }
        cout << dp[0][n - 1] << endl;
    }

	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Buyi.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值