UVA1629[Cake slicing] 棋盤動態規劃

題目鏈接


題目大意:一個矩形蛋糕上有好多個櫻桃,現在要做的就是切割最少的距離,切出矩形形狀的小蛋糕,讓每個蛋糕上都有一個櫻桃~問最少切割距離是?


解題報告:

因爲要分開處理切開的每塊蛋糕,所以我們可以想到用(r,c,w,h)來表示每個子矩陣。其中人 r,c 代表矩陣左上角的座標,w代表矩陣的寬,h代表矩陣的長。 dp[r][c][w][h]代表該矩陣切割的最小代價。我們可以枚舉橫着切/豎着切的每刀的代價。 預處理出每個矩陣的櫻桃個數。用前綴和思想算出每個矩陣的櫻桃個數(這裏需要預處理)。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 25;
int dp[maxn][maxn][maxn][maxn];
int be[maxn][maxn], val[maxn][maxn];

int chk(int r, int c, int w, int h){
    return val[r][c]-val[r+h][c]-val[r][c+w]+val[r+h][c+w];
}

int dfs(int r, int c, int w, int h){
    int &ans = dp[r][c][w][h];
    if( ans!=-1 ) return ans;
    if( chk(r,c,w,h)==1 ) return ans=0;
    if( chk(r,c,w,h)==0 ) return ans=0x3f3f3f3f;
    int tmp=0x3f3f3f3f;
    for ( int i=1; i<h; i++ ){
        if( chk(r,c,w,i) && chk(r+i,c,w,h-i) )
            tmp=min(tmp,dfs(r,c,w,i)+dfs(r+i,c,w,h-i)+w);
    }
    for ( int i=1; i<w; ++i ){
        if( chk(r,c,i,h) && chk(r,c+i,w-i,h) )
            tmp=min(tmp,dfs(r,c,i,h)+dfs(r,c+i,w-i,h)+h);
    }
    return ans=tmp;
}

int main(){
    int n, m, k, T=0;
    while( scanf("%d%d%d", &n, &m, &k )==3 && n ){
        memset(dp,-1,sizeof(dp));
        memset(be,0,sizeof(be));
        memset(val,0,sizeof(val));
        for ( int i=1; i<=k; i++ ){
            int x, y;
            scanf("%d%d", &x, &y );
            x--, y--;
            be[x][y]=1;
        }
        for ( int i=n-1; i>=0; --i )
            for ( int j=m-1; j>=0; --j )
                val[i][j]=val[i+1][j]+val[i][j+1]-val[i+1][j+1]+be[i][j];
        printf("Case %d: %d\n", ++T, dfs(0,0,m,n));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章