您的位置:首页 > 其它

UVa 1629 Cake Slicing DP

2015-12-15 05:50 309 查看
这题空了好久,虽然现在想出来了很激动,但是花的时间略长呀。。。
每切一次蛋糕就相当于一次状态转移。设某时刻蛋糕的坐上顶点为(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: