习题:Clear The Matrix(状压DP)
题目
思路
对于所有的变化,我们发现最多只有4*4
考虑\(dp[i][j]\)表示前i个数,i,i-1,i-2,i-3的状态为j的最小方案数
对于转移而言,其实我们只需要将所有的操作矩阵的左上角保证在i-3行即可
感觉这道题更像一个暴力
代码
#include<iostream>
#include<cstring>
using namespace std;
int n;
int w[5];
int f[1005];
int dp[1005][(1<<16)];
//第i列,压i,i+1,i+2,i+3列
int nxt[5][5];
//第i行放一个长度为j的矩阵
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=4;i++)
cin>>w[i];
for(int i=1;i<=4;i++)
{
for(int j=1;j<=n;j++)
{
char c;
cin>>c;
f[j]<<=1;
if(c=='*')
f[j]++;
}
}
for(int i=1;i<=4;i++)
{
for(int j=1;i+j-1<=4;j++)
{
int now=0;
int init[5][5]={};
for(int a=i;a<=i+j-1;a++)
for(int b=1;b<=j;b++)
init[a][b]=1;
for(int j=1;j<=4;j++)
for(int i=1;i<=4;i++)
now=(now<<1)+(!init[i][j]);
nxt[i][j]=now;
}
}
int bas=0;
for(int i=1;i<=4;i++)
{
bas<<=4;
bas|=f[i];
}
memset(dp,0x3f,sizeof(dp));
//cout<<dp[1][bas]<<endl;
dp[1][bas]=0;
//cout<<dp[1][bas]<<endl;
for(int i=1;i<=n+1;i++)
{
for(int j=(1<<16)-1;j>=0;j--)
{
if(dp[i][j]==dp[0][0])
continue;
if((j>>12)==0)
{
int now=(j<<4)|(f[i+4]);
dp[i+1][now]=min(dp[i+1][now],dp[i][j]);
}
for(int a=1;a<=4;a++)
for(int b=1;a+b-1<=4&&i+b-1<=n;b++)
dp[i][j&nxt[a][b]]=min(dp[i][j&nxt[a][b]],dp[i][j]+w[b]);
}
}
cout<<dp[n+1][0];
return 0;
}

浙公网安备 33010602011771号