leetcode [1444. 切披萨的方案数]
Posted BeicC
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode [1444. 切披萨的方案数]相关的知识,希望对你有一定的参考价值。
(https://leetcode-cn.com/problems/number-of-ways-of-cutting-a-pizza/)
猛一看感觉好吓人,其实最后做出来后在感觉就那样
这题第一眼看上去就像dp,知道这题考的是dp后我们接下来就要写出状态,很明显,切的刀数算一维,接下来我们还要去表示切剩下的披萨,仔细看题就会发现题目设计的很巧妙,它把每次切的披萨的上边或者左边给别人,这表明我们只要定义每块披萨的左上角就能表示这个披萨,即dp[k] [i] [j] 表示在用k刀切成左上角坐标为 i ,j披萨的方案数 ,状态写好然后定义边界即初始状态,原披萨的状态肯定符合题意,初始状态为dp[0] [0] [0] = 1;紧接着要写状态转移式,对于任意的dp [k] [i] [j] 这种状态,它对应着一块左上角坐标为[i] [j] 的披萨,我们想知道它的前一个状态不太容易(即怎么切能到这种状态),但我们很容易就知道它的下一个状态,无非就是横着切或者竖着切,只要符合题意,我们就可以进行状态转移,即:dp[k+1] [x] [y] += dp[k] [i] [j] ,这个转移式为什么是+=,很简单,拿样例1看一下,先切第一行在切第一列和先切第一列再切第一行得到得结果是不一样得,所以有写成+=, 最后在dp[K-1] 维统计一下就行了
const int maxn = 55;
const int MOD = 1e9+7;
int dp[15][maxn][maxn];
class Solution {
public:
int ways(vector<string>& pizza, int K) {
int n = pizza.size(),m = pizza[0].size();
for(int k = 0; k <= K; k++) for(int i = 0; i <= n; i++) for(int j = 0; j <= m; j++) dp[k][i][j] = 0;
dp[0][0][0] = 1; //初始化
for(int k = 0; k < K; k++){
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(dp[k][i][j] == 0) continue;
//H cut 横着切
int sum = 0;
for(int cuti = i; cuti < n-1; cuti++){
if(sum == 0){
for(int cutj = j; cutj < m; cutj++) if(pizza[cuti][cutj] == ‘A‘) sum++;
}
if(sum == 0) continue; // 符合题意才能转移
dp[k+1][cuti+1][j] = (dp[k+1][cuti+1][j]+dp[k][i][j]) % MOD;
}
//V cut 竖着切同理
sum = 0;
for(int cutj = j; cutj < m-1; cutj++){
if(sum == 0){
for(int cuti = i; cuti < n; cuti++) if(pizza[cuti][cutj] == ‘A‘) sum++;
}
if(sum == 0) continue;
dp[k+1][i][cutj+1] = (dp[k+1][i][cutj+1]+dp[k][i][j]) % MOD;
}
}
}
}
int ans = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
int sum = 0;
for(int ni = i; ni < n; ni++){
for(int nj = j; nj < m; nj++){
if(pizza[ni][nj] == ‘A‘) sum++;
}
}
if(sum) ans = (ans+dp[K-1][i][j]) % MOD; // 统计符合题意得答案,因为上面统计得答案是给别人得披萨中一定含有苹果,但你没有保证你剩下得一定有苹果,所以要统计一下
}
}
return ans;
}
};
以上是关于leetcode [1444. 切披萨的方案数]的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 1388. Pizza With 3n Slices(3n 块披萨)(DP)
Codeforces Round #437 C. Ordering Pizza