[UVA 1629]Cake slicing[记忆化搜索]

题目链接: [UVA 1629]Cake slicing
题意分析:一个矩形蛋糕上有好多个樱桃,现在要做的就是切割最少的距离,切出矩形形状的小蛋糕,让每个蛋糕上都有一个樱桃~问最少切割距离是?

解题思路:既然是切割蛋糕,可以感受到是一个无限切割的过程(递归?)反正有这种感觉存在。然后数据是20*20。那么就试试记忆化搜索。我们设dp[u][d][l][r]为u(up)为上届d(down)为下界,l为左界,r为右界的最小切割距离。边界就是当整块区域只有一个樱桃显然不用切割了,返回0。当整块区域没有樱桃时,这块区域就是无效的切割,设置为无穷。

个人感受:舍友提醒可以暴力的一个一个切割,可是脑袋里一点感觉都没有,递归的想法一点都没有,要哭瞎了TAT最后看了别人的才豁然开朗= =
具体代码如下:
#include
#include
#include
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
int n, m, dp[25][25][25][25];
bool has[25][25]; //记录格点是否有樱桃

int sum(int u, int d, int l, int r) //统计区域的樱桃数
{
    int ret = 0;
    for (int i = u + 1; i <= d; ++i)
        for (int j = l + 1; j <= r; ++j)
        {
            if (has[i][j]) ++ret;
            if (ret == 2) return 2; //超过两个也就是多个的情况可以统一递归处理,直接视为同一情况
        }
    return ret;
}

int dfs(int u, int d, int l, int r)
{
    int &ret = dp[u][d][l][r];
    if (ret != -1) return ret;
    int total = sum(u,d,l,r);
    if (total == 1) return ret = 0; //一个樱桃返回0,无需切割了
    if (!total) return ret = INF;  //没有樱桃,无效切割
    ret = INF;
    for (int i = u + 1; i < d; ++i) //水平切割
        ret = min(ret, dfs(u,i,l,r) + dfs(i,d,l,r) + r - l);
    for (int i = l + 1; i < r; ++i) //垂直切割
        ret = min(ret, dfs(u,d,l,i) + dfs(u,d,i,r) + d - u);
    return ret;
}

int main()
{
    int k, x, y, kase = 0;
    while(cin >> n >> m >> k)
    {
	   memset(dp, -1, sizeof dp);
	   memset(has, 0, sizeof has);
	   for (int i = 0; i < k; ++i) cin >> x >> y, has[x][y] = 1;
	   cout << "Case " << ++kase << ": " << dfs(0, n, 0, m) << '\n';
    }
	return 0;
}

你可能感兴趣的:([D]DP)