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;
}

AC记录

posted @ 2023-10-15 17:57  ccrui  阅读(11)  评论(0)    收藏  举报