ZOJ 3537 Cake

区间DP。

首先求凸包判断是否为凸多边形。

如果是凸多边形:假设现在要切割连续的一段点,最外面两个一定是要切一刀的,内部怎么切达到最优解就是求子区间最优解,因此可以区间DP。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

const int MAXN = 1000;
const int INF = 0x7FFFFFFF;
struct point
{
    int x, y;
};
point List[MAXN];
point a[MAXN];
int dp[MAXN][MAXN];
int Stack[MAXN], top;
int n, p;
int tot;

int cross(point p0, point p1, point p2)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p1.y - p0.y)*(p2.x - p0.x);
}
double dis(point p1, point p2)
{
    return sqrt((double)(p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y));
}
bool cmp(point p1, point p2)
{
    int tmp = cross(List[0], p1, p2);
    if (tmp>0) return true;
    else if (tmp == 0 && dis(List[0], p1)<dis(List[0], p2)) return true;
    else return false;
}
void init()
{
    int i, k;
    point p0;
    scanf("%d%d", &List[0].x, &List[0].y);
    p0.x = List[0].x;
    p0.y = List[0].y;
    k = 0;
    for (i = 1; i<n; i++)
    {
        scanf("%d%d", &List[i].x, &List[i].y);
        if ((p0.y>List[i].y) || ((p0.y == List[i].y) && (p0.x>List[i].x)))
        {
            p0.x = List[i].x;
            p0.y = List[i].y;
            k = i;
        }
    }
    List[k] = List[0];
    List[0] = p0;

    sort(List + 1, List + n, cmp);
}

void graham()
{
    int i;
    if (n == 1) { top = 0; Stack[0] = 0; }
    if (n == 2)
    {
        top = 1;
        Stack[0] = 0;
        Stack[1] = 1;
    }
    if (n>2)
    {
        for (i = 0; i <= 1; i++) Stack[i] = i;
        top = 1;

        for (i = 2; i<n; i++)
        {
            while (top>0 && cross(List[Stack[top - 1]], List[Stack[top]], List[i]) <= 0) top--;
            top++;
            Stack[top] = i;
        }
    }
}

int cost(int i, int j)
{
    return (abs(a[i].x + a[j].x)*abs(a[i].y + a[j].y)) % p;
}

void work()
{
    int tmp = top + 1; tot = 0;
    if (tmp != n) printf("I can‘t cut.\n");
    else
    {
        while (top != -1) a[tot++] = List[Stack[top--]];
        for (int r = 0, i = tot; r<tot - 1; r++, i++) a[i] = a[i - tot];

        tot = 2 * tot - 1;

        for (int i = 0; i < tot; i++)
            for (int j = 0; j < tot; j++)
                dp[i][j] = INF;

        for (int i = 0; i < tot; i++)
        {
            int st = i, en = st + 2 - 1;
            dp[st][en] = 0;
        }

        for (int i = 3; i<tmp; i++)
        {
            for (int j = 0; j<tot; j++)
            {
                int st = j, en = st + i - 1;
                if (en >= tot) continue;
                for (int k = st + 1; k <= en - 1; k++)
                    dp[st][en] = min(dp[st][en], dp[st][k] + dp[k][en] + cost(st, en));
            }
        }

        int ans = INF;
        for (int i = 0; i<tot; i++)
        {
            int st = i, en = st + tmp - 1 - 1;
            if (en>=tot) continue;
            ans = min(ans, dp[st][en]);
        }
        printf("%d\n", ans);
    }
}

int main()
{
    while (~scanf("%d%d", &n, &p))
    {
        init();
        graham();
        work();
    }
    return 0;
}
时间: 2024-12-06 18:06:29

ZOJ 3537 Cake的相关文章

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+最优三角剖分)

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)

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

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

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 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

zoj 3511 Cake Robbery(线段树)

题目链接:zoj 3511 Cake Robbery 题目大意:就是有一个N边形的蛋糕,切M刀,从中挑选一块边数最多的,保证没有两条边重叠. 解题思路:有多少个顶点即为有多少条边,所以直接按照切刀切掉点的个数排序,然后用线段树维护剩下的还有哪些点. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int