習題:Clear The Matrix(狀壓DP)
阿新 • • 發佈:2020-08-09
題目
思路
對於所有的變化,我們發現最多隻有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; }