UVa 1629 DP Cake slicing

本文介绍了一种通过动态规划解决蛋糕切割问题的方法,目标是最小化切割长度使得每块蛋糕上恰好有一个樱桃。代码实现中使用了递归与记忆化搜索来避免重复计算。

题意:

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

分析:

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

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

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

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 21;
 8 
 9 int n, m, k;
10 
11 int a[maxn][maxn], sum[maxn][maxn];
12 int dp[maxn][maxn][maxn][maxn];
13 
14 int tot(int u, int d, int l, int r)
15 {
16     return sum[d][r] - sum[d][l-1] - sum[u-1][r] + sum[u-1][l-1];
17 }
18 
19 int DP(int u, int d, int l, int r)
20 {
21     int& ans = dp[u][d][l][r];
22     if(ans >= 0) return ans;
23     if(tot(u, d, l, r) == 1) return ans = 0;
24 
25     ans = 1000000;
26     for(int i = u; i < d; i++)
27     {
28         if(tot(u, i, l, r) && tot(i+1, d, l, r))
29             ans = min(ans, (r - l + 1) + DP(u, i, l, r) + DP(i+1, d, l, r));
30     }
31     for(int i = l; i < r; i++)
32     {
33         if(tot(u, d, l, i) && tot(u, d, i+1, r))
34             ans = min(ans, (d - u + 1) + DP(u, d, l, i) + DP(u, d, i+1, r));
35     }
36     return ans;
37 }
38 
39 int main()
40 {
41     int kase = 0;
42     while(scanf("%d%d%d", &n, &m, &k) == 3)
43     {
44         memset(a, 0, sizeof(a));
45         memset(sum, 0, sizeof(sum));
46         memset(dp, -1, sizeof(dp));
47         for(int i = 0; i < k; i++)
48         {
49             int x, y; scanf("%d%d", &x, &y);
50             a[x][y] = 1;
51         }
52         for(int i = 1; i <= n; i++)
53             for(int j = 1; j <= m; j++)
54                 sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j];
55 
56         printf("Case %d: %d\n", ++kase, DP(1, n, 1, m));
57     }
58 
59     return 0;
60 }
代码君

 

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4777660.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值