題目大意:一個矩形蛋糕上有好多個櫻桃,現在要做的就是切割最少的距離,切出矩形形狀的小蛋糕,讓每個蛋糕上都有一個櫻桃~問最少切割距離是?
解題報告:
因爲要分開處理切開的每塊蛋糕,所以我們可以想到用(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));
}
}