ZOJ 3537

原题:
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

中文:

给你个蛋糕,让你分割。如果蛋糕不是多边形的,不能分。
否则蛋糕分割的时候有权重。蛋糕表现为在二维坐标系上的一个点集合,分割蛋糕需要在蛋糕上的两个点i和j上砍一刀,权重为cost[i, j] = |xi + xj| * |yi + yj| % p
现在问你把蛋糕全部分成三角形,是的最后的权重最小。

代码:

#include <bits/stdc++.h>
#define Vector Point

using namespace std;

const int maxn = 405;
const double eps = 1e-5;

struct Point
{
    int x,y;
    Point(int x=0,int y=0):x(x),y(y){}
};
bool operator < (const Point &a,const Point &b)//排序用,按照x的坐标从小到大,如果x相同,那么按照y从小到大
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}

Vector operator +(Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}//坐标点相加
Vector operator -(Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}//相减


int Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}

int ConvexHull(Point *P,int n,Point *ch)//p是所有点,n所有点的个数,ch里面记录形成凸包的点,返回凸包点的个数
{
    sort(P,P+n);
    int m=0;
    for(int i=0;i<n;i++)
    {
        while(m>1&&Cross(ch[m-1]-ch[m-2],P[i]-ch[m-2])<=0)
            m--;
        ch[m++]=P[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--)
    {
        while(m>k&&Cross(ch[m-1]-ch[m-2],P[i]-ch[m-2])<=0)
            m--;
        ch[m++]=P[i];
    }
    if(n>1)
        m--;
    return m;
}
int n,p;
Point ps[maxn],tps[maxn];
int cost[maxn][maxn];
int dp[maxn][maxn];
int Cost(int i,int j)
{
    return (abs(tps[i].x+tps[j].x)*abs(tps[i].y+tps[j].y))%p;
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>p)
    {
        for(int i=0;i<n;i++)
            cin>>ps[i].x>>ps[i].y;

        if(n<=3)
        {
            cout<<0<<endl;
            continue;
        }
        int m = ConvexHull(ps,n,tps);
        if(m!=n)
        {
            cout<<"I can't cut."<<endl;
            continue;
        }
        for(int i=0;i<n;i++)
        {
            for(int j=i+2;j<n;j++)
            {
                cost[i][j]=cost[j][i]=Cost(i,j);
            }
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                dp[i][j]=INT_MAX;
            }
        }
        for(int i=0;i<n-1;i++)
            dp[i][i+1]=0;
        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]+cost[i][k]+cost[k][j]);
                }
            }
        }
        cout<<dp[0][n-1]<<endl;
    }
    return 0;
}



解答:

首先判断给的蛋糕是不是凸包,如果是不是凸包直接输出I can’t cut.
如果是凸包,就要按照要求进行切割。此题算是最优三角剖分的改进,状态方程很容易得到。
此题有个小坑需要注意,也是最优三角剖分需要注意的点,就是进行dp的过程,要求提供的多边形点集一定是沿着一个方向的。

设置 d p [ i ] [ j ] dp[i][j] dp[i][j]表示第i个点到第j个点形成的多边形的最优剖分。
那么状态转移方程为
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k ] [ j ] + C o s t [ i ] [ k ] + C o s t [ j ] [ k ] ) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+Cost[i][k]+Cost[j][k]) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+Cost[i][k]+Cost[j][k])
因为要切出一个三角形,需要切两刀,注意,这里不要把i到j的边也算上。
因为再后续枚举更大的i到j的区间进行剖分时,小区间得到的底部会被当成大区间的三角形边来计算。如下图
在这里插入图片描述当枚举到dp[i1][j1]时,不需要计算cost[i1][j1]。
否则在计算dp[i1][j2],以k2为顶点时,边i1到j1会被重复计算。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值