zoj 3537 Cake(区间dp)

这道题目是经典的凸包的最优三角剖分,不过这个题目给的可能不是凸包,所以要提前判定一下是否为凸包,如果是凸包的话才能继续剖分,dp[i][j]表示已经排好序的凸包上的点i->j上被分割成一个个小三角形的最小费用,那么dp[i][j] = min(dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]),其中,(j >= i+ 3,i+1<=k<=j-1,cost[i][k]为连一条i到k的线的费用)。

上一个图,来自博客http://blog.csdn.net/woshi250hua/article/details/7824433

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define eps 1e-8
using namespace std;
typedef long long ll;
const int maxn = 500;
const int inf = (1 << 30);
int dp[maxn][maxn];
int cost[maxn][maxn];
struct point {
    int x, y;
};
point  p[maxn], convex[maxn];
bool cmp(const point &p1, const point &p2)
{
    return ((p1.y == p2.y && p1.x < p2.x) || p1.y < p2.y);
}
int x_multi(const point &p1, const point &p2, const point &p3)
{
    return ((p3.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p3.y - p1.y));
}

int sgn(double x)
{
    if (fabs(x) < eps)
        return 0;
    return x > 0 ? 1 : -1;
}
void convex_hull(point *p, point *convex, int n, int &len)//求凸包
{
    sort(p, p + n, cmp);
    int top = 1;
    convex[0] = p[0];
    convex[1] = p[1];
    for (int i = 2; i < n; i++)
    {
        while (top > 0 && x_multi(convex[top - 1], convex[top], p[i]) <= 0)
            top--;
        convex[++top] = p[i];
    }
    int tmp = top;
    for (int i = n - 2; i >= 0; i--)
    {
        while (top > tmp && x_multi(convex[top - 1], convex[top], p[i]) <= 0)
            top--;
        convex[++top] = p[i];
    }
    len = top;
}
int get_cost(const point &p1, const point &p2, const int &mod)
{
    return (abs(p1.x + p2.x) * abs(p1.y + p2.y)) % mod;
}
int main()
{
    int n, mod;
    while (~scanf("%d %d", &n, &mod))
    {
        for (int i = 0; i < n; i++)
            scanf("%d %d", &p[i].x, &p[i].y);
        int len;
        convex_hull(p, convex, n, len);
        if (len < n)//如果不是凸包的话,
            puts("I can‘t cut.");
        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] = get_cost(convex[i], convex[j], mod);//计算处各对角的费用
            for (int i = 0; i < n; i++)//初始化dp
            {
                for (int j = 0; j < n; j++)
                    dp[i][j] = inf;
                dp[i][i + 1] = 0;
            }
            for (int i = n - 3; i >= 0; i--)//必须逆序,因为dp[i][j] 是由dp[i][k], dp[k][j]推来的,而k是大于i的,
                for (int j = i + 2; j < n; j++)//同理顺序,因为k小于j
                    for (int k = i + 1; k <= j - 1; k++)
                        dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j] + cost[i][k] + cost[k][j]);
            printf("%d\n", dp[0][n - 1]);
        }
    }
    return 0;
}

时间: 2024-08-28 03:35:16

zoj 3537 Cake(区间dp)的相关文章

zoj 3537 Cake (凸包判定+区间dp)

Cake Time Limit: 1 Second      Memory Limit: 32768 KB You want to hold a party. Here's a polygon-shaped cake on the table. You'd like to cut the cake into several triangle-shaped parts for the invited comers. You have a knife to cut. The trace of eac

ZOJ 3537 Cake(凸包+区间DP)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3537 题目大意:给出一些点表示多边形顶点的位置,如果不是凸多边形(凸包)则不能切,直接输出"I can't cut."切多边形时每次只能在顶点和顶点间切,每切一次的花费为 cost(i, j) = |xi + xj| * |yi + yj| % p.问把多边形切成最多个不相交三角形的最小代价是多少. 解题思路:先求出凸包,接着可以用区间DP解决,设dp

ZOJ 3537 Cake 求凸包 区间DP

题意:给出一些点表示多边形顶点的位置(如果多边形是凹多边形就不能切),切多边形时每次只能在顶点和顶点间切,每切一次都有相应的代价.现在已经给出计算代价的公式,问把多边形切成最多个不相交三角形的最小代价是多少. 思路:首先判断多边形是否是凸多边形,之后就是区间dp了. 求出凸包后,按逆时针来看. 设置dp[i][j]为从顶点i到顶点j所围成凸多边形的最优解. 枚举切点k (i < k < j) dp[i][j] = min(dp[i][k] + dp[k][j] + cost[i][k] + c

zoj 3537 Cake (凸包确定+间隔dp)

Cake Time Limit: 1 Second      Memory Limit: 32768 KB You want to hold a party. Here's a polygon-shaped cake on the table. You'd like to cut the cake into several triangle-shaped parts for the invited comers. You have a knife to cut. The trace of eac

ZOJ - 3537 —— Cake

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23543 1. 因为没有三个点在同一直线上,即每个点都是多边形的一个顶点而不会有点在某条边上,所以要判断这个多边形是不是凸多边性,可以用像凸包问题那样做,得到的凸包的关节点以及它们的个数num,若num==n (全体点的个数),那么是凸多边形:否则,不是凸多边形. 2. 如果判断是凸多边形后,就要开始正式的DP了. 我们都知道,这种成环的数组的DP,可以将环拆开,变成区

ZOJ 3537 Cake

区间DP. 首先求凸包判断是否为凸多边形. 如果是凸多边形:假设现在要切割连续的一段点,最外面两个一定是要切一刀的,内部怎么切达到最优解就是求子区间最优解,因此可以区间DP. #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int MAXN = 1000; con

ZOJ - 3537 Cake (凸包+区间DP+最优三角剖分)

Description You want to hold a party. Here's a polygon-shaped cake on the table. You'd like to cut the cake into several triangle-shaped parts for the invited comers. You have a knife to cut. The trace of each cut is a line segment, whose two endpoin

ZOJ 3537 Cake (区间DP,三角形剖分)

题意: 给出平面直角坐标系上的n个点的坐标,表示一个多边形蛋糕,先判断是否是凸多边形,若否,输出"I can't cut.".若是,则对这个蛋糕进行3角形剖分,切n-3次变成n-2份三角形蛋糕给小伙伴吃,但是每切一次需要一个费用,公式是:cost[i][j] = |xi + xj| * |yi + yj| % p 表示在两点i和j之间切一刀的费用.问最少费用是多少? 思路: 判断是否凸多边形需要用到求凸包的Andrew算法,时间复杂度为O(nlogn),然后判断凸包内的点数是否为n就行

ZOJ 3905 Cake(贪心+dp)

动态规划题:dp[i][j]表示有i个Cake,给了Alice j个,先按照b排序,这样的话,能保证每次都能成功给Alice Cake,因为b从大到小排序,所以Alice选了j个之后,Bob最少选了j个,所以i>=2*j, 并且每次Alice选的时候Bob已经选过了.所以当i>=2 * j的时候Alice一定能选. 所以dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] + ary[i].a); dp[i - 1][j]表示Alice不选第i个,dp[i