CF1198D 题解
看到区间和极小的数据范围,就想到了区间 DP。
设对 DP 状态是关键,我们可以这样设置状态:\(dp_{x,y,z,t}\) 表示左上角为 \((x,y)\) ,右下角为 \((z,t)\) 的矩形中所有的 # 都被覆盖的最小代价。
对于每一个 \(dp_{x,y,z,t}\),我们把它沿 \(k\) 竖着分割为 \(dp_{x,y,k,t}\) 和 \(dp_{k+1,y,z,t}\) 或横着分为 \(dp_{x,y,z,k}\) 和 \(dp_{x,k+1,z,t}\)。
以样例 1 举例:
3
##|#
#.|#
##|#
\(dp_{1,1,3,3}\) 沿 \(k=2\) 竖着分割为 \(dp_{1,1,2,3}\) 和 \(dp_{3,1,3,3}\)。
3
###
#.#
---
###
也可以把它沿 \(k=2\) 横着分割为 \(dp_{1,1,3,2}\) 和 \(dp_{1,3,3,3}\)。
现在题目也转换为了一个 \(O(n^5)\) 的区间 DP 了。
AC 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int a[100][100],qz[100][100];
int dp[60][60][60][60];
void ghh(int x,int y){
for(int l=1;l<=n-x+1;l++){//枚举x
int l2=l+x-1;//对应z
for(int r=1;r<=n-y+1;r++){//枚举y
int r2=r+y-1;//对应t
for(int k=l;k<l2;k++){
dp[l][r][l2][r2]=min(dp[l][r][l2][r2],dp[l][r][k][r2]+dp[k+1][r][l2][r2]);
//竖着分割
}
for(int k=r;k<r2;k++){
dp[l][r][l2][r2]=min(dp[l][r][l2][r2],dp[l][r][l2][k]+dp[l][k+1][l2][r2]);
//横着分割
}
dp[l][r][l2][r2]=min(dp[l][r][l2][r2],max(x,y));//直接覆盖
}
}
}
signed main(){
scanf("%lld",&n);
memset(dp,0x3f,sizeof(dp));//初始化
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char c;
cin>>c;
if(c=='#')dp[i][j][i][j]=1;
else dp[i][j][i][j]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ghh(i,j);
}
}//区间DP
printf("%lld",dp[1][1][n][n]);
return 0;
}

浙公网安备 33010602011771号