现在的位置: 首页 > 综合 > 正文

UVa #1629 Cake slicing (习题9-3)

2018年10月13日 ⁄ 综合 ⁄ 共 1657字 ⁄ 字号 评论关闭

预处理保存下以(0,0)为左上角、(r, c)为右下角的矩形内梅子的个数,则以(r1,c1)为左上角、(r2,c2)为右下角的大矩形内梅子的个数为cnt[r2][c2] - cnt[r1-1][c2] - cnt[r2][c1-1] + cnt[r1-1][c1-1],注意边界。预处理复杂度为O(n),n为矩形格子总数。则可以在O(1)内判断某个区域内还有几个梅子。

状态和状态转移方程都比较好设计。

倒是有个奇怪的现象:我的记忆化搜索代码中,有两个被注释掉了的if语句。加上这两个if语句,运行时间会增加50%(从1.1s变为1.6s)。不知是什么原因。

Run TIme: 1.082s

#define UVa  "9-3.1629.cpp"     //Cake slicing

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

//Global Variables.
const int maxn = 20 + 5, INF = 1<<30;
int n, m, k;            //n:rows, m:columns
int cherry[maxn][maxn];
int d[maxn][maxn][maxn][maxn];
int cnt[maxn][maxn];
////

int areacnt(int r1, int c1, int r2, int c2) {       //count the # of cherries in range ((r1, c1),(r2,c2))
    int a=cnt[r2][c2], b=0, c=0, d=0;
    if(r1)
        b = cnt[r1-1][c2];
    if(c1)
        c = cnt[r2][c1-1];
    if(r1&&c1)
        d = cnt[r1-1][c1-1];
    return a - b - c + d;
}

int dp(int r1, int c1, int r2, int c2) {
    int& ans = d[r1][c1][r2][c2];
    if(ans != -1) return ans;

    if(areacnt(r1, c1, r2, c2) == 1) return ans = 0;
    else if(areacnt(r1, c1, r2, c2) == 0) return ans = INF;

    ans = INF;

    for(int i = c1; i < c2; i ++) {       //vertical cut
//        if(areacnt(r1, c1, r2, i) && areacnt(r1, i+1, r2, c2)) {
            int d1, d2, len;
            d1 = dp(r1, c1, r2, i);
            d2 = dp(r1, i+1, r2, c2);
            len = r2-r1+1;
            ans = min(ans, d1 + d2 + len);
//        }
    }
    for(int i = r1; i < r2; i ++) {       //horizontal cut
//        if(areacnt(r1, c1, i, c2) && areacnt(i+1, c1, r2, c2)) {
            int d1, d2, len;
            d1 = dp(r1, c1, i, c2);
            d2 = dp(i+1, c1, r2, c2);
            len = c2-c1+1;
            ans = min(ans, d1 + d2 + len);
//        }
    }

    return ans;
}


int main() {
    int kase = 1;
    while(scanf("%d%d%d", &n, &m, &k) != EOF) {
        memset(cherry, 0, sizeof(cherry));

        int r, c;
        for(int i = 0; i < k; i ++) {
            scanf("%d%d", &r, &c);
            cherry[r-1][c-1] = 1;
        }

        memset(cnt, 0, sizeof(cnt));
        int linecnt;
        for(int i = 0; i < n; i ++) {
            linecnt = 0;
            for(int j = 0; j < m; j ++) {
                linecnt += cherry[i][j];
                cnt[i][j] = linecnt;
                if(i) cnt[i][j] += cnt[i-1][j];
            }
        }
        memset(d, -1, sizeof(d));

        printf("Case %d: %d\n", kase ++, dp(0, 0, n-1, m-1));
    }

    return 0;
}

抱歉!评论已关闭.