链接:
1444. 切披萨的方案数
题意:
给定一个矩阵,其中含有多个苹果,需要切割k-1次,每次可以切割多行/多列,需要保证切割两个部分都有苹果,移除靠上/靠右的部分,对留下部分进行后续的切割,求有几种切割方法
解:
男人不能快算法需要快!
这题需要通过两部分节约时间,一部分是动态规划,一部分是前缀和
这好像还是第一次写二维前缀和(好像),主要是要记得移除重复部分,由于每次保留的是靠下/靠左的部分,所以求的是已i j
为起点的右下角和
动态规划部分,我们需要一个三维的DP[k][i][j]
,分别代表从i j
开始的右下角矩阵,成功切割k-1刀的方案数量
初始值是DP[1][i][j]
=(sum[i][j] > 0)
,即这一整块上存在苹果
递推公式需要判断行切和列切,判断条件非常巧妙,是整体苹果数量 > 切割后剩下的苹果数量,公式是整体+=切割后的部分
整体DP[temp][i][j]
,假设在i2位置进行切割,则判断sum[i][j] > sum[i2][j]
,若为真即计算DP[temp][i][j]+=DP[temp-1][i2][j]
,要注意切割后所需的切割数-1
实际代码:
#include<bits/stdc++.h>
using namespace std;
constexpr static int Mod=1E9+7;
int ways(vector<string>& pizza, int k)
{int lgrow=pizza.size(),lgcol=pizza[0].length();vector<vector<int>>sum(lgrow+1,vector<int>(lgcol+1));vector<vector<vector<int>>>dp(k+1,vector<vector<int>>(lgrow+1,vector<int>(lgcol+1)));//初始化 for(int i=lgrow-1;i>=0;i--){for(int j=lgcol-1;j>=0;j--){sum[i][j]=sum[i+1][j]+sum[i][j+1]-sum[i+1][j+1]+(pizza[i][j]=='A');//二维前缀和 矩阵计算 dp[1][i][j]=sum[i][j]>0;}}//dp递推 for(int dp_k=2;dp_k<=k;dp_k++){for(int i=lgrow-1;i>=0;i--){for(int j=lgcol-1;j>=0;j--){//行切割for(int i2=lgrow-1;i2>i;i2--){if(sum[i][j]>sum[i2][j])//切出来的有苹果{dp[dp_k][i][j]+=dp[dp_k-1][i2][j];dp[dp_k][i][j]%=Mod;}}//列切割for(int j2=lgcol-1;j2>j;j2--){if(sum[i][j]>sum[i][j2])//切出来的有苹果{dp[dp_k][i][j]+=dp[dp_k-1][i][j2];dp[dp_k][i][j]%=Mod;}}}}}return dp[k][0][0];
}
int main()
{int k;cin>>k;vector<string> pizza;string s;while(cin>>s) pizza.push_back(s);int ans=ways(pizza,k);cout<<ans<<endl;return 0;
}
限制:
1 <= rows, cols <= 50
rows == pizza.length
cols == pizza[i].length
1 <= k <= 10
pizza 只包含字符 'A' 和 '.' 。