[codeforces]903F Clear The Matrix

原题链接 :903F Clear The Matrix

分析

题目大意

给定一个(4 imes n) 的矩阵,上面有'.'和'*'现在你可以用(1 imes 1),(2 imes 2),(3 imes 3),(4 imes 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
",dp[n][0]);
    return 0;
}
/* mk[i][j]表示在第一行第i个位置摆一个大小为j的方块,它覆盖的状态*/	
原文地址:https://www.cnblogs.com/onglublog/p/9874654.html