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 each cut is a line segment, whose two endpoints are two vertices
of the polygon. Within the polygon, any two cuts ought to be disjoint. Of course, the situation that only the endpoints of two segments intersect is allowed.

The cake‘s considered as a coordinate system. You have known the coordinates of vexteces. Each cut has a cost related to the coordinate of the vertex, whose formula is
costi, j = |xi + xj| * |yi + yj| % p. You want to calculate the minimum cost.

NOTICE: input assures that NO three adjacent vertices on the polygon-shaped cake are in a line. And the cake is not always a convex.

Input

There‘re multiple cases. There‘s a blank line between two cases. The first line of each case contains two integers,
N and p (3 ≤ N, p ≤ 300), indicating the number of vertices. Each line of the following
N lines contains two integers, x and y (-10000 ≤
x, y ≤ 10000), indicating the coordinate of a vertex. You have known that no two vertices are in the same coordinate.

Output

If the cake is not convex polygon-shaped, output "I can‘t cut.". Otherwise, output the minimum cost.

Sample Input

3 3
0 0
1 1
0 2

Sample Output

0

题意:

给定n个点的坐标,先问这些点是否能组成一个凸包,如果是凸包,问用不相交的线来切这个凸包使得凸包只由三角形组成,根据costi, j = |xi + xj| * |yi + yj| % p算切线的费用,问最少的切割费用。

思路:

先判定凸包,求凸包后看点的个数有没有变化。

然后区间dp,dp[i][j]表示切凸多边形i~j时的最小花费,特殊情况顶点个数为2或者3时不用切了为0.

如图i~j引入两条切线ik和kj将凸多边形分为两个凸多边形和一个三角形。

转移dp[i][j]=min(dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]);

cost[i][j]为切i、j两点时的花费,当j=i+1时花费为0.(凸多边形为三角形)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 105
#define MAXN 100005
#define mod 1000000000
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-8
typedef long long ll;
using namespace std;

int cmp(int x)
{
    if(fabs(x)<eps) return 0;
    if(x>0) return 1;
    return -1;
}
int sqr(int x)
{
    return x*x;
}
struct point
{
    int x,y;
    point(){};
    point(int a,int b):x(a),y(b){};
    void input()
    {
        scanf("%d%d",&x,&y);
    }
    friend point operator +(const point &a,const point &b)
    {
        return point(a.x+b.x,a.y+b.y);
    }
    friend point operator -(const point &a,const point &b)
    {
        return point(a.x-b.x,a.y-b.y);
    }
    friend bool operator ==(const point &a,const point &b)
    {
        return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;
    }
    friend point operator *(const point &a,const int &b)
    {
        return point(a.x*b,a.y*b);
    }
    friend point operator *(const int &a,const point &b)
    {
        return point(a*b.x,a*b.y);
    }
    friend point operator /(const point &a,const int &b)
    {
        return point(a.x/b,a.y/b);
    }
    int norm()
    {
        return sqrt(sqr(x)+sqr(y));
    }
};
int det(const point &a,const point &b)
{
    return a.x*b.y-a.y*b.x;
}
int dot(const point&a,const point &b)
{
    return a.x*b.x+a.y*b.y;
}
int dist(const point &a,const point &b)
{
    return (a-b).norm();
}

struct polygon_convex
{
    vector<point>p;
    polygon_convex(int Size=0)
    {
        p.resize(Size);
    }
};
bool comp_less(const point &a,const point &b)
{
    return cmp(a.x-b.x)<0||cmp(a.x-b.x)==0&&cmp(a.y-b.y)<0;
}
polygon_convex convex_hull(vector<point> a)
{
    polygon_convex res(2*a.size()+5);
    sort(a.begin(),a.end(),comp_less);
    a.erase(unique(a.begin(),a.end()),a.end());
    int m=0;
    for(int i=0;i<a.size();i++)
    {
        while(m>1&&cmp(det(res.p[m-1]-res.p[m-2],a[i]-res.p[m-2]))<=0) m--;
        res.p[m++]=a[i];
    }
    int k=m;
    for(int i=int(a.size())-2;i>=0;--i)
    {
        while(m>k&&cmp(det(res.p[m-1]-res.p[m-2],a[i]-res.p[m-2]))<=0) m--;
        res.p[m++]=a[i];
    }
    res.p.resize(m);
    if(a.size()>1) res.p.resize(m-1);
    return res;
}

int n,m,ans;
int dp[305][305],cost[305][305];
vector<point> pp;

int main()
{
    int i,j,t;
    while(~scanf("%d%d",&n,&m))
    {
        vector<point> pp;
        point tmp;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&tmp.x,&tmp.y);
            pp.push_back(tmp);
        }
        polygon_convex tb=convex_hull(pp);
        if(tb.p.size()!=n) printf("I can't cut.\n");
        else
        {
            if(n==3)
            {
                printf("0\n");
                continue ;
            }
            memset(cost,0,sizeof(cost));
            for(i=0;i<n;i++)
            {
                for(j=i+2;j<n;j++)
                {
                    cost[i][j]=(abs(tb.p[i].x+tb.p[j].x)*abs(tb.p[i].y+tb.p[j].y))%m;
                }
            }
            memset(dp,0x3f,sizeof(dp));
            for(i=0;i<n-2;i++)
            {
                dp[i][i+1]=0;
                dp[i][i+2]=0;
            }
            dp[n-2][n-1]=0;
            for(int len=4;len<=n;len++)
            {
                for(i=0;i<n;i++)
                {
                    j=i+len-1;
                    if(j>=n) break ;
                    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;
}
/*
3 3
0 0
1 1
0 2

4 10
0 0
2 0
0 2
2 2

5 11
1 1
1 3
3 1
4 2
3 4
*/

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

时间: 2024-12-21 10:52:42

zoj 3537 Cake (凸包判定+区间dp)的相关文章

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 3469 Food Delivery(区间DP)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4255 题意:n个人订餐.n个人位于一条线上,饭店也在这条线上.每个人有一个脾气值p.若第i分钟得到他预定的饭不满意度为p*i.送饭人的速度已知.求一种送饭顺序使得总不满意度最小. 思路:设f[i][j][0],f[i] [j][1]分别表示将[i,j]区间的送完,最后停在左边或右边的最小不满意度.那么我们在DPf[i][j][0]时可以从f[i+1][j]进行转 移

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 3892 Available Computation Sequence 区间dp

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5595 题意:给出n个字符串,里面包含'*', '.', '^', '!'这四个运算符,以及小写字母(表示向量)和数字. 四个运算符都有不同的运算规则.问添上括号后,可以组成多少个不同的算式(不能进行非法运算). 思路:简单区间DP,把一个运算符看成一位. dp[i][j][1]表示第i-j位运算结果为数字的情况有多少种. dp[i][j][0]表示第i-j位运算结果

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