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
", ++kase, DP(1, n, 1, m));
57     }
58 
59     return 0;
60 }
代码君
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4777660.html