题目描述
有一个n*m大小的蛋糕,上面有k个樱桃,现在我们需要把这个蛋糕切成k份,使每份蛋糕上有一个樱桃,问最小切割长度和。(切割一刀必须切到底)
样例输入
3 4 3
1 2
2 3
3 2
样例输出
Case 1: 5
题解
dp[ a ][ b ][ c ][ d ]表示以(a,b)为左上端点,(c,d)为右下端点的矩形切成每份一个樱桃的最小切割长度。由于每次只能横切或竖切,我们可以枚举切割点,递归求解。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=25; const int inf=2e9+7; int dp[maxn][maxn][maxn][maxn],ans,n,m,k; bool p[maxn][maxn]; template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int work(int a,int b,int c,int d){ if(dp[a][b][c][d]!=-1) return dp[a][b][c][d]; int cnt=0; for(int i=a;i<=c;i++) for(int j=b;j<=d;j++){ if(p[i][j]) cnt++; } if(cnt==1) return dp[a][b][c][d]=0; if(cnt==0) return dp[a][b][c][d]=inf; int Min=inf; for(int i=a;i<c;i++) Min=min(Min,work(a,b,i,d)+work(i+1,b,c,d)+d-b+1); for(int i=b;i<d;i++) Min=min(Min,work(a,b,c,i)+work(a,i+1,c,d)+c-a+1); return dp[a][b][c][d]=Min; } int main(){ int temp=0,x,y; while(scanf("%d%d%d",&n,&m,&k)!=EOF){ memset(p,false,sizeof(p)); memset(dp,-1,sizeof(dp)); for(int i=1;i<=k;i++){ read(x),read(y); p[x][y]=true; } ans=work(1,1,n,m); printf("Case %d: %d ",++temp,ans); } return 0; }