这题空了好久,虽然现在想出来了很激动,但是花的时间略长呀。。。
每切一次蛋糕就相当于一次状态转移。设某时刻蛋糕的坐上顶点为(a, b),右下顶点为(c, d),将这块蛋糕切成只剩一个樱桃产生的切割线长度最短为d ( a, b, c, d)。
原来是想根据樱桃的位置来切蛋糕,但是很难实现。考虑到横竖共m + n 种切法,可以枚举状态。
纵向:min { d ( a, b, c, j ) + d ( a, j + 1, c, d ) + d - b + 1 } ( b <= j < d )
横向:min { d ( a, b, i, d ) + d ( i + 1, b, c, d ) + c - a + 1 } ( a <= i < c )
枚举时需要判断:当矩形内只有一个点时,d() 值为0;当切割出的矩形不含樱桃时,舍弃此种情况。d[][][][]初始化为-1。
代码:
#include <cstdio>
#include <cstring>
const int maxn = 25;
int n, m, k;
int dp[maxn][maxn][maxn][maxn], rec[maxn][maxn];
int dpl(int a, int b, int c, int d) {
if (dp[a][b][c][d] > -1) return dp[a][b][c][d];
int &res = dp[a][b][c][d];
int dot = rec[c][d] + rec[a - 1][b - 1] - rec[a - 1][d] - rec[c][b - 1];
//printf("1:%d,%d %d,%d value:%d\n", a, b, c, d, res);
if (dot == 1) return res = 0;
int min = 1000000;
for (int j = b; j < d; j++) {
// divide into d(a, b, c, j) and d(a, j + 1, c, d)
dot = rec[c][j] + rec[a - 1][b - 1] - rec[a - 1][j] - rec[c][b - 1];
if (dot == 0) continue;
dot = rec[c][d] + rec[a - 1][j] - rec[a - 1][d] - rec[c][j];
if (dot == 0) continue;
int t = dpl(a, b, c, j) + dpl(a, j + 1, c, d) + c - a + 1;
if (t < min) min = t;
}
for (int i = a; i < c; i++) {
// divide into d(a, b, i, d) and d(i + 1, b, c, d)
dot = rec[i][d] + rec[a - 1][b - 1] - rec[a - 1][d] - rec[i][b - 1];
if (dot == 0) continue;
dot = rec[c][d] + rec[i][b - 1] - rec[i][d] - rec[c][b - 1];
if (dot == 0) continue;
int t = dpl(a, b, i, d) + dpl(i + 1, b, c, d) + d - b + 1;
if (t < min) min = t;
}
res = min;
//printf("2:%d,%d %d,%d value:%d\n", a, b, c, d, res);
return res;
}
int main() {
#ifndef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
int kase = 1;
while (~scanf("%d%d%d", &n, &m, &k)) {
memset(rec, 0, sizeof(rec));
memset(dp, -1, sizeof(dp));
int x, y;
for (int i = 0; i < k; i++) {
scanf("%d%d", &x, &y);
rec[x][y] = 1;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
rec[i][j] += rec[i - 1][j];
//printf("%d%c", rec[i][j], " \n"[j == m]);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
rec[i][j] += rec[i][j - 1];
//printf("%d%c", rec[i][j], " \n"[j == m]);
}
printf("Case %d: %d\n", kase++, dpl(1, 1, n, m));
}
return 0;
}