[codeforces]903F Clear The Matrix
原题链接 :903F Clear The Matrix
分析
题目大意
给定一个\(4\times n\) 的矩阵,上面有'.'和'*'现在你可以用\(1\times 1\),\(2\times 2\),\(3\times 3\),\(4\times 4\)这四种'.'矩阵覆盖这个矩阵,要求覆盖后的矩阵只剩'.'。
每一次覆盖有价值,四种大小的矩阵价值不同。
求最小的总价值。
其实状压dp是挺明显的,本来想打一发搜索,但是状态设计有点麻烦。
考虑到矩阵宽度只有4,可以很明显来一发状压dp。
状压最重要的是设计状态。
dp[i][s]表示前i行已经全部被覆盖了,现在的状态为s。
这样子很明显可以得到,当第一行全为'.'的时候,我们可以递推到第i+1行。
然后我们预处理出用于覆盖矩形的状态。
mk[i][k]表示矩形左上角放在第一行的第i个位置,矩形的大小为k,他的覆盖状态。
然后递推就是\(dp[i][s\&mk[i][k]]=min\{dp[i][s]+w[k]\}\)。
这样子我们跑一遍dp就可以推出最终状态。
时间复杂度O(能过)。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
int read(){
char c;int num,f=1;
while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
while(c=getchar(), isdigit(c))num=num*10+c-'0';
return f*num;
}
int n,a[10],f[1009],ans;
int mk[10][10],m[10][10];
int dp[1009][(1<<16)+4],qwq=0;
char c;
void init(){
n=read();
for(int i=1;i<=4;i++)a[i]=read();
for(int i=0;i<4;i++){
for(int j=0;j<n;j++){
cin>>c;
f[j]<<=1;
f[j]+=(c=='*');
}
}
for(int i=0;i<4;i++){
for(int j=1;j<=4-i;j++){
for(int k=0;k<4;k++)
for(int p=0;p<4;p++)
m[k][p]=1;
for(int k=0;k<j;k++)
for(int p=0;p<j;p++)
m[k][i+p]=0;
ans=0;
for(int k=3;k>=0;k--){
for(int p=0;p<4;p++){
ans=(ans<<1)+m[k][p];
}
}
mk[i][j]=ans;
}
}
}
int main()
{
memset(dp,0x3f,sizeof(dp));
init();
//cout<<mk[0][3]<<endl;
for(int i=3;i>=0;i--)
qwq*=16,qwq+=f[i];
dp[0][qwq]=0;
for(int i=0;i<=n;i++){
for(int s=(1<<16)-1;s>=0;s--){
if(dp[i][s]>=0x3f3f3f3f-10)continue;
if(!(s&15)){
int ss=(f[i+4]<<12)|(s>>4);
dp[i+1][ss]=min(dp[i+1][ss],dp[i][s]);
}
for(int k=0;k<4;k++)
for(int p=1;p<=4-k;p++)
dp[i][s&mk[k][p]]=min(dp[i][s&mk[k][p]],dp[i][s]+a[p]);
}
}
printf("%d\n",dp[n][0]);
return 0;
}
/* mk[i][j]表示在第一行第i个位置摆一个大小为j的方块,它覆盖的状态*/