UESTC The Urge to Merge(状态压缩)

本文介绍了一个关于3*n矩阵的最大价值合并问题,并通过动态规划的方法进行解答。问题的核心在于如何通过不同状态间的转移来实现每个格子价值的最大化。

题目大意:给出一个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…80‰3i0ˆ40ˆ4¡Á0…70ˆ00…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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值