您的位置:首页 > 其它

UVa 1629 DP Cake slicing

2015-09-02 09:21 183 查看
题意:

一块n×m的蛋糕上有若干个樱桃,要求切割若干次以后,每块蛋糕上有且仅有1个樱桃。求最小的切割长度。

分析:

d(u, d, l, r)表示切割矩形(u, d, l, r)所需要的最小切割长度。

我们可以枚举第一刀切割的方向和位置,在切割之前还要判断一下这一刀是否合法,防止出现切出来的某一个小块蛋糕上没有樱桃。

递归的边界就是这块矩形上只有一个樱桃的时候,那么就不能再切了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 21;

int n, m, k;

int a[maxn][maxn], sum[maxn][maxn];
int dp[maxn][maxn][maxn][maxn];

int tot(int u, int d, int l, int r)
{
return sum[d][r] - sum[d][l-1] - sum[u-1][r] + sum[u-1][l-1];
}

int DP(int u, int d, int l, int r)
{
int& ans = dp[u][d][l][r];
if(ans >= 0) return ans;
if(tot(u, d, l, r) == 1) return ans = 0;

ans = 1000000;
for(int i = u; i < d; i++)
{
if(tot(u, i, l, r) && tot(i+1, d, l, r))
ans = min(ans, (r - l + 1) + DP(u, i, l, r) + DP(i+1, d, l, r));
}
for(int i = l; i < r; i++)
{
if(tot(u, d, l, i) && tot(u, d, i+1, r))
ans = min(ans, (d - u + 1) + DP(u, d, l, i) + DP(u, d, i+1, r));
}
return ans;
}

int main()
{
int kase = 0;
while(scanf("%d%d%d", &n, &m, &k) == 3)
{
memset(a, 0, sizeof(a));
memset(sum, 0, sizeof(sum));
memset(dp, -1, sizeof(dp));
for(int i = 0; i < k; i++)
{
int x, y; scanf("%d%d", &x, &y);
a[x][y] = 1;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j];

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

return 0;
}


代码君
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: