洛谷P2331题解

洛谷P2331题解

  • 显然要用动规,主要入手点是发现 m < = 2 m <= 2 m<=2,所以想到先考虑m = 1时的情况,再看是否能套用到m = 2的情况
  • 当m = 1是,显然是最大子段和的升级版,选k个子段,这时想到开三维dp[i][j][k]表示现在做了1-i行,选了j个子段(子矩阵),第i行状态为k(核心),若选,则状态为1,否则,状态为0
  • 状态转移顺推以及逆推均可,以逆推为例, d p [ i ] [ j ] [ k ] = m a x ( d p 2 [ i ] [ j ] [ k ] , d p [ i − 1 ] [ j − v a l [ w ] [ k ] ] [ w ] + ( k = = 1 ? a [ i ] [ 1 ] : 0 ) ) ; dp[i][j][k] = max( dp2[i][j][k] , dp[i - 1][j - val[w][k]][w] + ( k == 1 ? a[i][1] : 0 )) ; dp[i][j][k]=max(dp2[i][j][k],dp[i1][jval[w][k]][w]+(k==1?a[i][1]:0));按照这个方程算一遍即可,主要注意最好开数组val来保存从状态x转化到状态y所至少需要多多少子矩阵
  • 顺推就是用当前状态更新未知状态,转移方程是 d p [ i + 1 ] [ j + v a l 2 [ k ] [ w ] ] [ w ] = m a x ( d p [ i + 1 ] [ j + v a l [ k ] [ w ] ] [ w ] , d p [ i ] [ j ] [ k ] ) + c a l ( i , w ) dp[i + 1][j + val2[k][w]][w] = max( dp[i + 1][j + val[k][w]][w] , dp[i][j][k] ) + cal(i , w) dp[i+1][j+val2[k][w]][w]=max(dp[i+1][j+val[k][w]][w],dp[i][j][k])+cal(i,w),几乎同逆推
  • 当m = 2时,只要改一下val[w][k]的值以及后面的式子即可
  • 代码
//顺推
# include <iostream>
# include <cstdio>

using namespace std ;

const int NR = 105 ;

int n , m , t ;
int dp1[NR][20][2] ;
int dp2[NR][15][5] ;
int a[NR][3] ;
int val1[2][2] = 
{
	{ 0 , 1 } ,
	{ 0 , 0 } 
} ;

int val2[5][5] = 
{
	{ 0 , 1 , 1 , 1 , 2 } ,
	{ 0 , 0 , 1 , 1 , 1 } ,
	{ 0 , 1 , 0 , 1 , 1 } ,
	{ 0 , 1 , 1 , 0 , 2 } ,
	{ 0 , 0 , 0 , 1 , 0 } 
} ;

void do1()
{
	for ( int i = 0 ; i < NR ; i++ )
		for ( int j = 0 ; j <= 15 ; j++ )
			for ( int k = 0 ; k <= 1 ; k++ )
				dp1[i][j][k] = -1e9 ;
	for ( int j = 0 ; j <= 15 ; j++ )
		dp1[0][j][0] = 0 ;
	for ( int i = 0 ; i < n ; i++ )
		for ( int j = 0 ; j <= t ; j++ )
		{
			for ( int k = 0 ; k <= 1 ; k++ )
			{
				if ( k == 1 )
					dp1[i][j][k] += a[i][1] ;
				for ( int w = 0 ; w <= 1 ; w++ )
				{
					if ( j + val1[k][w] > t )
						continue ;
					dp1[i + 1][j + val1[k][w]][w] = max( 
					dp1[i + 1][j + val1[k][w]][w] , dp1[i][j][k] ) ;
				}
			}
		}
	int ans = -1e9 ;
	for ( int i = 0 ; i <= 1 ; i++ )
	{
		if ( i == 1 )
			dp1[n][t][i] += a[n][1] ;
		ans = max( ans , dp1[n][t][i] ) ;
	}
	printf("%d\n" , ans) ;
}

void do2()
{
	for ( int i = 0 ; i < NR ; i++ )
		for ( int j = 0 ; j <= 15 ; j++ )
			for ( int k = 0 ; k <= 4 ; k++ )
				dp2[i][j][k] = -1e9 ;
	for ( int j = 0 ; j <= 15 ; j++ )
		dp2[0][j][0] = 0 ;
	for ( int i = 0 ; i < n ; i++ )
		for ( int j = 0 ; j <= t ; j++ )
		{
			for ( int k = 0 ; k <= 4 ; k++ )
			{
				if ( k == 1 )
					dp2[i][j][k] += a[i][1] ;
				if ( k == 2 )
					dp2[i][j][k] += a[i][2] ;
				if ( k == 3 || k == 4 )	
					dp2[i][j][k] += a[i][1] + a[i][2] ;
				for ( int w = 0 ; w <= 4 ; w++ )
				{
					if ( j + val2[k][w] > t )
						continue ;
					dp2[i + 1][j + val2[k][w]][w] = max( 
					dp2[i + 1][j + val2[k][w]][w] , dp2[i][j][k] ) ;
				}
			}
		}
	int ans = -1e9 ;
	for ( int i = 0 ; i <= 4 ; i++ )
	{
		if ( i == 1 )
			dp2[n][t][i] += a[n][1] ;
		if ( i == 2 )
			dp2[n][t][i] += a[n][2] ;
		if ( i == 3 || i == 4 )	
			dp2[n][t][i] += a[n][1] + a[n][2] ;
		ans = max( ans , dp2[n][t][i] ) ;
	}
	printf("%d\n" , ans) ;
}

int main()
{
	scanf( "%d%d%d" , &n , &m , &t ) ;
	for ( int i = 1 ; i <= n ; i++ )
	{
		for ( int j = 1 ; j <= m ; j++ )
		{
			scanf( "%d" , &a[i][j] ) ;
		}
	}
	if ( m == 1 )
	{
		do1() ;
	}
	else
	{
		do2() ;
	}
	return 0 ;
}
//逆推
# include <iostream>
# include <cstdio>
# include <algorithm>

using namespace std ;

const int NR = 105 ;

int n , m , t ;
int dp1[NR][15][2] ;
int dp2[NR][15][5] ;
int a[NR][3] ;
int val2[5][5] = 
{
	{ 0 , 1 , 1 , 1 , 2 } ,
	{ 0 , 0 , 1 , 1 , 1 } ,
	{ 0 , 1 , 0 , 1 , 1 } ,
	{ 0 , 1 , 1 , 0 , 2 } ,
	{ 0 , 0 , 0 , 1 , 0 } 
} ;

void do1()
{
	for ( int j = 0 ; j < 15 ; j++ )
		dp1[0][j][1] = -1e9 ;
	for ( int j = 0 ; j < 15 ; j++ )
		dp1[0][j][0] = 0 ;
	
	for ( int i = 1 ; i <= n ; i++ )
		for ( int j = 0 ; j <= t ; j++ )
			for ( int k = 0 ; k <= 1 ; k++ )
			{
				dp1[i][j][k] = -1e9 ;
				if ( j - k >= 0 )
					dp1[i][j][k] = dp1[i - 1][j - k][0] ;
				dp1[i][j][k] = max( dp1[i][j][k] , dp1[i - 1][j][1] ) ;
				if ( k )
					dp1[i][j][k] += a[i][1] ;
			}
	printf( "%d\n" , max( dp1[n][t][0] , dp1[n][t][1] ) ) ;
}

int calc( int p , int q )
{
	int ans = 0 ;
	if ( q == 1 || q == 3 || q == 4 )
		ans += a[p][1] ;
	if ( q == 2 || q == 3 || q == 4 )
		ans += a[p][2] ;
	return ans ;
}

void do2()
{
	for ( int i = 0 ; i <= n ; i++ )
		for ( int j = 0 ; j <= t ; j++ )
			for ( int k = 0 ; k <= 4 ; k++ )
				dp2[i][j][k] = -1e9 ;
	for ( int j = 0 ; j < 15 ; j++ )
		dp2[0][j][0] = 0 ;
	
	for ( int i = 1 ; i <= n ; i++ )
		for ( int j = 0 ; j <= t ; j++ )
		{
			for ( int k = 0 ; k <= 4 ; k++ )
			{
				for ( int w = 0 ; w <= 4 ; w++ )
				{
					if ( j >= val2[w][k] )
					{
						dp2[i][j][k] = max( dp2[i][j][k] , 
						dp2[i - 1][j - val2[w][k]][w] ) ;
					}
				}
				if ( k == 1 )
					dp2[i][j][k] += a[i][1] ;
				if ( k == 2 )
					dp2[i][j][k] += a[i][2] ;
				if ( k == 3 || k == 4 )	
					dp2[i][j][k] += a[i][1] + a[i][2] ;
			}
		}
	int ans = -1e9 ;
	for ( int i = 0 ; i <= 4 ; i++ )
		ans = max( ans , dp2[n][t][i] ) ;
	printf("%d\n" , ans) ;
}

int main()
{
	scanf( "%d%d%d" , &n , &m , &t ) ;
	for ( int i = 1 ; i <= n ; i++ )
	{
		for ( int j = 1 ; j <= m ; j++ )
		{
			scanf( "%d" , &a[i][j] ) ;
		}
	}
	if ( m == 1 )
	{
		do1() ;
	}
	else
	{
		do2() ;
	}
	return 0 ;
}
  • 大坑点:空矩阵也算子矩阵!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值