zoj3537 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

Author:  LI, Zezhou

Contest: ZOJ Monthly, September 2011




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

思路:经典的最优三角剖分模型。

  首先,先判断给定的n个点的坐标是否构成凸包;之后我们选以1和n为起始点的凸包,由于切割的线不能相交,所以选择1到n之间的任意一点s组成三角形之后,该凸包被分成三部分,一个是以1和s为起始点的凸包k0,一个是以s和n为起始点的凸包k1,以及1和n和s构成的三角形;那么我们按照这个思路继续切割k0和k1,直至所剩均为三角形。

所以设dp[i][j]为以i和j为起始点的凸包被切成一个个三角形所花的最小费用。那么状态转移方程为:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j+cost[i][k]+cos[k][j]),其中i<k<j,记忆化搜索之。详见程序:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=300+100;
const double eps=1e-10;
const int inf=0x3fffffff;
int n,m;
int cost[MAXN][MAXN],dp[MAXN][MAXN];
struct point
{
    double x,y;
}p[MAXN],poly[MAXN];
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    return x<0 ? -1 : 1;
}
bool operator ==(const point &a,const point &b)
{
    return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0 ;
}
bool cmp(point a,point b)
{
    if(a.x==b.x)
        return a.y<b.y;
    return a.x<b.x;
}
double cross(point p1,point p2,point p0)
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int Andrew(int n)
{
    sort(p,p+n,cmp);
    int top=-1;
    for(int i=0;i<n;i++)
    {
        while(top>0 && cross(p[i],poly[top],poly[top-1])>=0)
            top--;
        poly[++top]=p[i];
    }
    int len=top;
    for(int i=n-2;i>=0;i--)
    {
        while(top!=len && cross(p[i],poly[top],poly[top-1])>=0)
            top--;
        poly[++top]=p[i];
    }
    return top;
}
int get_cost(point a,point b)
{
    return ((int)(abs(a.x+b.x)*abs(a.y+b.y)))%m;
}
void dfs(int i,int j)
{
    if(j-i==1)
    {
        dp[i][j]=0;
        return ;
    }
    if(dp[i][j]!=-1)
        return ;
    dp[i][j]=inf;
    for(int k=i+1;k<j;k++)
    {
        dfs(i,k); dfs(k,j);
        dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+cost[i][k]+cost[k][j]);
    }

}
int main()
{
    //freopen("text.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=0;i<n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        int top=Andrew(n);
        if(top<n)
        {
            printf("I can't cut.\n");
            continue;
        }
        for(int i=0;i<n;i++)
            for(int j=i+2;j<n;j++)
                cost[i][j]=cost[j][i]=get_cost(poly[i],poly[j]);
        memset(dp,-1,sizeof(dp));
        dfs(0,n-1);
        printf("%d\n",dp[0][n-1]);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值