题目大意:给出一个3*n的矩阵,相邻的两个各自可以合并成一个,合并以后的格子的数值是原来两个数值的乘积,每个格子只能合并一次。要求求出这个矩阵每个格子的数值的和最大值。
思路:因为只有三行,把这三行用的状态用三个二进制数表示,dp(i,j)表示到达第j列的时候,这一列状态为i时,可以达到的最大数值。如果i的二进制数第1位为0,说明这一位已经不能合并了,即这个数要么跟前面一列的数合并了,要么跟第j列的数合并了。如果这一位为1,表示这一位可以跟后面的合并,即这一位在目前的状态下不跟任何一个格子合并。对于某一位为0的情况下,首先考虑它跟前面一列合并的情况,然后再考虑它跟本列合并的情况。跟本列合并的只有三种情况,即000,001,100。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[10][1005];
int matrix[4][1005];
int rec[4];
int main(){
// freopen("data.txt","r",stdin);
ios::sync_with_stdio(false);
int n;
int kase=0;
while(cin>>n){
if(n==0)break;
matrix[0][0]=0;
matrix[1][0]=0;
matrix[2][0]=0;
matrix[3][0]=0;
for(int i=1;i<=3;++i){
for(int t=1;t<=n;++t){
cin>>matrix[i][t];
}
}
memset(dp,0,sizeof(dp));
dp[0][1]=0;
dp[1][1]=matrix[2][1]*matrix[3][1];
dp[4][1]=matrix[1][1]*matrix[2][1];
int tot=1<<3;
for(int i=2;i<=n;++i){
for(int t=0;t<tot;++t){//0…80‰3i0ˆ40ˆ4¡Á0…70ˆ00…1
for(int j=0;j<tot;++j){//i-1 Line
rec[0]=1;rec[1]=0;rec[2]=1;
for(int k=0;k<3;++k){
if((t&(1<<k))==0)rec[k]=0;
else rec[k]=1;
}
int can=1;
int tmp=0;
for(int k=0;k<3;++k){
if(rec[k]==0&&((j&(1<<k))==0)){can=0;break;}
if(rec[k]==1)continue;
tmp=tmp+matrix[k+1][i]*matrix[k+1][i-1];
}
if(!can)continue;
dp[t][i]=max(dp[t][i],dp[j][i-1]+tmp);
}
if(t==0){
for(int j=0;j<tot;++j){
if(j&(1<<0)){
dp[t][i]=max(dp[t][i],dp[j][i-1]+matrix[1][i]*matrix[1][i-1]+matrix[2][i]*matrix[3][i]);
}
if(j&(1<<2)){
dp[t][i]=max(dp[t][i],dp[j][i-1]+matrix[3][i]*matrix[3][i-1]+matrix[1][i]*matrix[2][i]);
}
}
}
if(t==1){
for(int j=0;j<tot;++j){
dp[t][i]=max(dp[t][i],dp[j][i-1]+matrix[3][i]*matrix[2][i]);
}
}
if(t==4){
for(int j=0;j<tot;++j){
dp[t][i]=max(dp[t][i],dp[j][i-1]+matrix[1][i]*matrix[2][i]);
}
}
}
}
int ans=0;
for(int i=0;i<tot;++i){
ans=max(ans,dp[i][n]);
}
cout<<"Case "<<++kase<<": ";
cout<<ans<<endl;
}
return 0;
}