poj1036Gangsters<DP>
链接:http://poj.org/problem?id=1036
题意:
有个伸缩门,大小在[0,k]内变动,在每个状态处,门的大小既可以 +1 或者 -1,且初始时是在0处,现在有n个高贵度,身材和到来时间不尽相同的人来饭店,求怎样安排门的变化使得能够进去的人的高贵度之和最大;
思路:
比较常见的一种动规,从N个点中选出任意个点,使其价值最大;
先按时间或其他顺序排序,使数据有序化,然后f[i]代表选择该点最大可得到的价值,通过枚举前一个选择的点来得到f[i]的值;
状态方程:dp[i][j]=max(dp[i+1][j],dp[i+1][j-1],dp[i+1][j+1]);
这类选择类的DP基本都这样,唯一要注意的是,这类题目中,最终阶段保存的结果不一定就是最优结果
View Code
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 6 const int N=102; 7 const int T=30002; 8 int dp[2][N]; 9 bool mark[T]; 10 11 struct Gan 12 { 13 int t, p, s; 14 }g[N]; 15 16 inline int Max( int a, int b ) 17 { 18 return a>b?a:b; 19 } 20 21 int main( ) 22 { 23 int n, k, m; 24 while(scanf( "%d%d%d", &n,&k, &m )==3){ 25 memset( mark, 0, sizeof mark ); 26 for( int i=1; i<=n; ++ i ){ 27 scanf( "%d", &g[i].t ); 28 mark[g[i].t]=1; 29 } 30 for( int i=1; i<=n; ++ i ){ 31 scanf( "%d", &g[i].p ); 32 } 33 for( int i=1; i<=n; ++ i ){ 34 scanf( "%d", &g[i].s ); 35 } 36 memset(dp, 0, sizeof(dp)); 37 for( int i=0;i<=m; ++ i ){ 38 for( int j=0; j<=i&&j<=k; ++ j ){ 39 int w=0; 40 if( mark[i] ){ 41 for( int l=1; l<=n; ++ l ){ 42 if( g[l].s==j&& g[l].t==i ){ 43 w+=g[l].p; 44 } 45 } 46 } 47 if( j==0 )dp[i%2][j]=Max( dp[1-i%2][j], dp[1-i%2][j+1] ); 48 else if( j==k ) dp[i%2][j]=Max( dp[1-i%2][j], dp[1-i%2][j-1] ); 49 else dp[i%2][j] = Max(Max(dp[1-i%2][j], dp[1-i%2][j-1]), dp[1-i%2][j+1]); 50 dp[i%2][j] += w; 51 } 52 } 53 int ans=0; 54 for( int i=0; i<=k; ++ i ){ 55 if(ans<dp[m%2][1])ans=dp[m%2][i]; 56 } 57 printf( "%d\n", ans ); 58 } 59 60 return 0; 61 }