1629 - Cake slicing(DP)

花了近2个小时终于AC,好爽。。

一道类似于最优矩阵链乘的题目,受《切木棍》那道题的启示,该题的原理也是一样的,仅仅只是变成了且面积。那么对应的也要添加维度 。

显然要完整的表示状态,最少要用四维数组。分别表示它的两个对角线顶点的坐标 。   然后横切或者纵切,递归需找更小的矩形,直到矩形内仅仅剩一个樱桃的时候返回0

那么问题就是如何高速的推断一个矩形内有多少个樱桃,于是决定再开一个数组记录这个矩形内樱桃的个数。一開始就是在这个地方超时(开了个五重循环) ,后来想到一个折中的办法,将时间复杂度分散开 。

受到高效那章求区间和的方法,我们能够先用一个二维数组求出每一行的每一个区间内樱桃的个数,这样就将时间复杂度大大减少了 。

本来以为这样会非常快,结果好像也不快,其它人在递归的时候求的樱桃个数居然也过了。

。或许是由于用记忆化搜索递归会剪掉非常多不必要的计算 。

细节參见代码:

#include<bits/stdc++.h>
using namespace std;
const int INF = 1000000;
int n,m,k,maxn = 0,d[22][22][22][22],cnt[22][22][22][22],f[22][22];
struct point{
    int x,y;
}c[405];
int dp(int ux,int uy,int dx,int dy) {
    int& ans = d[ux][uy][dx][dy];
    if(cnt[ux][uy][dx][dy] == 1) return 0;//递归边界
    if(ans >= 0) return ans;
    ans = INF;
    if(uy != dy) for(int i=uy;i<=dy;i++) { //纵切
        if(cnt[ux][uy][dx][i]>0 && cnt[ux][i][dx][dy]>0)
        ans = min(ans,dp(ux,uy,dx,i)+dp(ux,i+1,dx,dy) + dx - ux + 1);
    }
    if(ux != dx) for(int i=ux;i<=dx;i++) { //横切
        if(cnt[ux][uy][i][dy]>0 && cnt[i][uy][dx][dy]>0)
        ans = min(ans,dp(i+1,uy,dx,dy) + dp(ux,uy,i,dy) + dy - uy + 1);
    }
    return ans;
}
void init() {
    for(int i=1;i<=k;i++) {
        for(int r=1;r<=n;r++) {
            for(int j=1;j<=m;j++) {//先求出每一行的樱桃个数
                if(c[i].x == r && c[i].y <= j) f[r][j]++;
            }
        }
    }
    for(int ux=1;ux<=n;ux++) {
        for(int uy=1;uy<=m;uy++) {
            for(int dx=ux;dx<=n;dx++) {
                for(int dy=uy;dy<=m;dy++) {
                    int v = 0;
                    for(int i=ux;i<=dx;i++) {
                        v += f[i][dy] - f[i][uy-1]; //分别求出一部分答案。将时间复杂度分散
                    }
                    cnt[ux][uy][dx][dy] = v;
                }
            }
        }
    }
}
int main() {
    while(~scanf("%d%d%d",&n,&m,&k)) {
        memset(f,0,sizeof(f));
        memset(d,-1,sizeof(d));
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=k;i++) scanf("%d%d",&c[i].x,&c[i].y);
        init();
        printf("Case %d: %d\n",++maxn,dp(1,1,n,m));
    }
    return 0;
}

时间: 2024-08-24 01:10:20

1629 - Cake slicing(DP)的相关文章

UVA 1629 - Cake slicing(记忆化搜索)

记忆化搜索, 枚举所有的切割方式dp[r1][c1][r2][c2]表示(r1, c1) (r2, c2)之间的蛋糕切割所需要的最小花费count_num用来计算(r1, c1) (r2, c2)之间有多少个草莓递推边界当count_num为1是返回0 init()为对草莓数的一个预处理,使得在O(1)的时间内可以计算区域内的草莓数 总状态数为m * n * m * n决策有n + m种 时间复杂度为O((n + m) * n * n * m * m) /*583ms*/ 1 #include<

uva 1629切蛋糕(dp)

有一个n行m列的网格蛋糕,上面有一些樱桃,求使得每块蛋糕上都有一个樱桃的切割最小长度 思路:dp. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue&

hdu 5623 KK&#39;s Number(dp)

问题描述 我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N\left(1\leq N\leq 5*{10}^{4} \right)N(1≤N≤5∗10?4??)个数,每次KK都会先拿数.每次可以拿任意多个数,直到NN个数被拿完.每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终KK的得分减去对手的得分会是多少? 输入描述 第一行一个数T\left( 1\leq T\leq 10\right)T(1≤T≤10),表示数据组

Ural 1353 Milliard Vasya&#39;s Function(DP)

题目地址:Ural 1353 定义dp[i][j],表示当前位数为i位时,各位数和为j的个数. 对于第i位数来说,总可以看成在前i-1位后面加上一个0~9,所以状态转移方程就很容易出来了: dp[i][j]=dp[i][j]+dp[i][j-1]+dp[i][j-2]+.......+dp[i][j-9]: 最后统计即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <

HDU 4908 (杭电 BC #3 1002题)BestCoder Sequence(DP)

题目地址:HDU 4908 这个题是从m开始,分别往前DP和往后DP,如果比m大,就比前面+1,反之-1.这样的话,为0的点就可以与m这个数匹配成一个子串,然后左边和右边的相反数的也可以互相匹配成一个子串,然后互相的乘积最后再加上就行了.因为加入最终两边的互相匹配了,那就说明左右两边一定是偶数个,加上m就一定是奇数个,这奇数个的问题就不用担心了. 代码如下: #include <iostream> #include <stdio.h> #include <string.h&g

Sicily 1146:Lenny&#39;s Lucky Lotto(dp)

题意:给出N,M,问有多少个长度为N的整数序列,满足所有数都在[1,M]内,并且每一个数至少是前一个数的两倍.例如给出N=4, M=10, 则有4个长度为4的整数序列满足条件: [1, 2, 4, 8], [1, 2, 4, 9], [1, 2, 4, 10], [1, 2, 5, 10] 分析:可用动态规划解题,假设dp[i][j],代表满足以整数i为尾数,长度为j的序列的个数(其中每一个数至少是前一个数的两倍).那么对于整数i,dp[i][j] 等于所有dp[k][j-1]的和,其中k满足:

UVA542 - France &#39;98(dp)

UVA542 - France '98(dp) 题目链接 题目大意:之前题目意思还以为看懂了,其实没看明白,它已经把各个选手分在各自所在的区域里面,这就意味着第一次的PK的分组已经确定,而且冠军必须是从两个左右分区出来的胜利者才有机会pk冠军. 解题思路:那么从1-16这个大的区间内诞生出来的冠军可能是来自左边,也可能是右边,然后再左边右边的子区间递归找出冠军.f[i][l][r]表示l-r这个区间的胜利者是i的概率,那么假设i在区间的最左边,f[i][l][r] = Sum(f[i][l][m

HDU 4968 Improving the GPA(dp)

HDU 4968 Improving the GPA 题目链接 dp,最大最小分别dp一次,dp[i][j]表示第i个人,还有j分的情况,分数可以减掉60最为状态 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int t, avg, n; double dp1[15][405], dp2[15][405]; double get(int x) { if

URAL 1167. Bicolored Horses (DP)

题目链接 题意 :农夫每天都会放马出去,然后晚上把马赶入马厩,于是让马排成一行入马厩,但是不想马走更多的路,所以让前p1匹入第一个马厩,p2匹马入第二个马厩…………但是他不想让他的任何一个马厩空着,所有的马都必须入马厩.有两种颜色的马,如果 i 匹黑马与 j 匹白马同在一个马厩,不愉快系数是 i * j,总系数就是k个系数相加.让总系数最小. 思路 : dp[i][j] 代表的是前 i 个马厩放 j 匹马的最小不愉快系数值. 1 //1167 2 #include <cstdio> 3 #in