HDU3905 DP

通过这题看出DP的功底还是不行啊,仍需提高。

题意:一节课有N分钟,ZZ需要睡M分钟,每分钟都有其效益值,ZZ若听课,则必须连续听L分钟以上。问能获得的最大效益值。M分钟的睡眠可以不连续
题解:动态规划,状态设计:dp[i][j]表示第i分钟已经睡过j分钟可以获得的最大效益。状态转移可以分第i分钟听课或者睡觉。若第i分钟睡觉,dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]),若听课,对于每个k( 0 <= k <= i - l),求dp[k][j] + sum[i] - sum[k]的最大值。求最大值的时候用一个数组维护,不用另写一个循环。在第i-1次循环时求得的最大值到第i次时,全都加上了a[i](第i分钟的效益值),[0,i-1-l]区间内的最大值可以通过上一轮循环(i-1)的最大值加上第i分钟的效益值得到,然后和dp[i-l][j]+sum[i]-sum[i-l]比较取较大值即为[0,i-l]区间内的最大值。sum[i]是前i分钟总的效益值

code:

#include <cstdio>
#include <cstring>
#define N 1010
#define Max( a, b ) ( a > b ? a : b )
using namespace std;

int dp[ N ];

int cmp[ N ], sum[ N ];

void init ( int n ) {
	memset ( cmp, 0, sizeof ( cmp ) );
	for ( int i = 1 ; i < n ; ++i ) {
		sum[ i ] += sum[ i - 1 ];
	}
}

int solve ( int n, int m, int l ) {
	init ( n );
	for ( int j = 0 ; j <= m ; ++j ) {
		int div = j;
		memset ( dp, 0, sizeof ( dp ) );
		for ( int i = j + 1 ; i <= n ; ++i ) {
			dp[ i ] = Max ( dp[ i ], cmp[ i - j ] );
			if ( i - l < j ) continue;
			if ( dp[ div ] + sum[ i - 1 ] - sum[ div - 1 ] <
				dp[ i - l ] + sum[ i - 1 ] - sum[ i - l - 1 ] ) {
				div = i - l;
			}
			dp[ i ] = Max ( dp[ i ], dp[ div ] + sum[ i - 1 ] - sum[ div - 1 ] );
			cmp[ i - j ] = Max ( cmp[ i - j ], dp[ i ] );
		}
	}
	return dp[ n ];
}

int main () {
	int n, m, l;
	while ( scanf ( "%d%d%d", &n, &m, &l ) != EOF ) {
		for ( int i = 0 ; i < n ; ++i ) {
			scanf ( "%d", &sum[ i ] );
		}
		printf ( "%d\n", solve ( n, m, l ) );
	}
	return 0;
}



你可能感兴趣的:(div)