解题思路:既然是切割蛋糕,可以感受到是一个无限切割的过程(递归?)反正有这种感觉存在。然后数据是20*20。那么就试试记忆化搜索。我们设dp[u][d][l][r]为u(up)为上届d(down)为下界,l为左界,r为右界的最小切割距离。边界就是当整块区域只有一个樱桃显然不用切割了,返回0。当整块区域没有樱桃时,这块区域就是无效的切割,设置为无穷。
个人感受:舍友提醒可以暴力的一个一个切割,可是脑袋里一点感觉都没有,递归的想法一点都没有,要哭瞎了TAT最后看了别人的才豁然开朗= =#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> 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; }