一、题目
二、题目
由于能填的只有
这
种,可以考虑状压,相当于考虑
这样的方格如何去填。设
为考虑到第
列,前
列都已经处理好了,
的状态压缩(.
是0*
是1)为
的最小花费。
转移就枚举操作的子矩阵(有一边在当前列上),可以预处理子矩阵的状态,把他们并起来得到新的状态。如果当前列已经被处理完,就可以转移到下一列的状态了。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 1005;
const int inf = 0x3f3f3f3f;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,pos,w[5],f[M],a[5][5],b[5][5],dp[M][1<<16];
signed main()
{
n=read();
for(int i=1;i<=4;i++)
w[i]=read();
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;j<=4-i+1;j++)
{
for(int k=1;k<=4;k++)
for(int l=1;l<=4;l++)
a[k][l]=1;
for(int k=1;k<=j;k++)
for(int l=0;l<j;l++)
a[k][i+l]=0;
int now=0;
for(int k=4;k>=1;k--)
for(int l=1;l<=4;l++)
now=(now<<1)+a[k][l];
b[i][j]=now;
}
memset(dp,0x3f,sizeof dp);
for(int i=4;i>=1;i--)
{
pos<<=4;
pos+=f[i];
}
dp[1][pos]=0;
for(int i=1;i<=n;i++)
for(int j=(1<<16)-1;j>=0;j--)
{
if(dp[i][j]==inf) continue;
if(!(j&15))
{
int now=(f[i+4]<<12)|(j>>4);
dp[i+1][now]=min(dp[i+1][now],dp[i][j]);
}
for(int k=1;k<=4;k++)
for(int l=1;l<=4-k+1;l++)
dp[i][j&b[k][l]]=min(dp[i][j&b[k][l]],dp[i][j]+w[l]);
}
printf("%d\n",dp[n][0]);
}