zoukankan      html  css  js  c++  java
  • 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.
    ");
        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
    ", ans);
        }
    }
    
    int main()
    {
        while (~scanf("%d%d", &n, &p))
        {
            init();
            graham();
            work();
        }
        return 0;
    }
  • 相关阅读:
    无法卸载Visual Studio 2005,提示:"H:\vs\vs_setup.msi could not be opened"
    在两个DB的table之间同步数据
    用于标记系统是否需要重启动的注册表键值
    提高性能——存储过程最佳实践 [译自MSDN]
    几个常见的位运算问题
    [存档] 非递归后根遍历二叉树
    [存档] 用真值表设计非递归二叉树遍历算法
    补码
    卸载Google Chrome导致Outlook, Word不能打开超链接
    编程题: 将一个矩阵(二维数组)顺时针旋转90度
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5224122.html
Copyright © 2011-2022 走看看