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

 

posted @ 2016-02-28 10:02  Fighting_Heart  阅读(198)  评论(0编辑  收藏  举报