uva - 1629 Cake slicing(dp)

題意:n行m列的網格蛋糕上有一些櫻桃,每次可以用刀沿着網格線切成兩塊,問要想使最終每塊蛋糕上恰好有一顆櫻桃,切得最小長度。

直接正向去想怎樣切感覺不好想,但是可以反過來,像區間拼接一樣考慮把當個網格的蛋糕拼接起來,拼接的長度就是要切的長度。

dp[a][b][c][d]表示從(a, b)點到(c, d)的矩形範圍內拼接的最短長度,num[a][b][c][d]用來統計這個矩形區域內的櫻桃數量。如果這一塊區域內只有一塊(或者沒有)櫻桃那麼拼接長度一定是0。對於一塊區域可以是上下兩個矩形也可以是左右兩個矩形拼接起來的,那麼枚舉拼接的位置就可以了,注意如果拼接的兩個矩形有一箇中沒有櫻桃是不符合條件的,要跳過。

整個思想和區間dp一致,只是區間dp是一維的,而這個是二維的。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int dp[21][21][21][21];
int num[21][21][21][21];
int main() {
    int ks = 1, n, m, q, r, c;
    while(~scanf("%d%d%d", &n, &m, &q)) {
        memset(num, 0, sizeof(num));
        memset(dp, 0x3f, sizeof(dp));
        while(q--) {
            scanf("%d%d", &r, &c);
            num[r - 1][c - 1][r][c] = 1;
        }
        for(int rl = 1; rl <= n; rl++) {
            for(int cl = 1; cl <= m; cl++) {
                for(int br = 0; br + rl <= n; br++) {
                    for(int bc = 0; bc + cl <= m; bc++) {
                        int er = br + rl, ec = bc + cl;
                        num[br][bc][er][ec] = max(num[br][bc][br + 1][ec] + num[br + 1][bc][er][ec], num[br][bc][er][bc + 1] + num[br][bc + 1][er][ec]);
//                        printf("%d %d %d %d %d\n", br, bc, er, ec, num[br][bc][er][ec]);
                        if(num[br][bc][er][ec] <= 1) {
                            dp[br][bc][er][ec] = 0;
                            continue;
                        }
                        for(int j = br + 1; j < er; j++) {
                            if(!num[br][bc][j][ec] || !num[j][bc][er][ec]) continue;
                            if(dp[br][bc][j][ec] + dp[j][bc][er][ec] + cl < dp[br][bc][er][ec]) {
                                dp[br][bc][er][ec] = dp[br][bc][j][ec] + dp[j][bc][er][ec] + cl;
                            }
                        }
                        for(int j = bc + 1; j < ec; j++) {
                            if(!num[br][bc][er][j] || !num[br][j][er][ec]) continue;
                            if(dp[br][bc][er][ec] > dp[br][bc][er][j] + dp[br][j][er][ec] + rl)
                                dp[br][bc][er][ec] = dp[br][bc][er][j] + dp[br][j][er][ec] + rl;
                        }
                    }
                }
            }
        }
        printf("Case %d: %d\n", ks++, dp[0][0][n][m]);
    }
    return 0;
}
/**
3 4 3
1 2
2 3
3 2
**/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章