Ecust 406 sleeping at work
#include <stdio.h> #include <memory.h> int f[510][100],v[510][60]; int a[510]; int max(int a,int b){return a>b?a:b;} int add(int s,int b); int main() { int n,k,m,j,i,T,g,maxx,temp; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;i++) scanf("%d",i+a); if((n-n/(k+1))<m) { printf("impossible\n"); continue; } memset(f,0,sizeof(f)); for(i=1;i<=n;i++) for(j=0;j<=k&&j<=i;j++) v[i][j]=add(i,j); for(i=1;i<=n;i++) for(j=(i>m?m:i);j>=0;j--) { temp=0; for(g=(j>k?k:j);g>=0;g--) { if(i==g&&j==g) temp=max(temp,v[i][g]); else if(i==g+1&&j-g>0) { if(j==0)continue; else break; } else temp=max(temp,f[i-g-1][j-g]+v[i][g]); } f[i][j]=temp; } maxx=f[1][m]; for(i=2;i<=n;i++)if(maxx<f[i][m])maxx=f[i][m]; printf("%d\n",maxx); } return 0; } int add(int s,int b) { int i,j,sum=0; for(i=b;i>0;i--) sum+=i*a[s+i-b]; return sum; }
Sleeping at Work
Time Limit: 4000MS | Memory Limit: 100000K | |
Total Submits: 148 | Accepted: 42 | |
Description
Input
Output
Sample Input
2 10 3 3 10 10 9 6 5 4 2 1 4 4 10 6 1 1 2 3 4 5 6 7 8 9 10
Sample Output
57 impossible
Hint
- 0 < T <= 100
- 0 < N <= 500
- 0 < M <= 50
- 0 < R <= 50
- 0 <= ai < N
- You can only start and stop sleeping exactly when the minute indicator on the clock changes.
Source
题意:某人要参加编程比赛所以在工作时睡觉补充体力,在所给的工作时间内每个时间点都有一个恢复值,并且连续睡觉时也会有奖励,奖励方式如:连续睡3个时间点,则补充1*a1+2*a2+3*a3; 问在满足睡觉时间内体力恢复的最大值。额,还有一点就是某人的boss会在某人连续睡k个单位时间时发现,前提不能被boss发现。
思路:这是一道很明显的DAG,开始还有点想歪了,突然发觉类似分组的背包。好吧,回到正题来,
只是简单的一维背包的话肯定不行,因为当前所作的决策不仅仅只由前一状态决定,所以用一个二维数组;
既然是类似分组的背包,那么我们可以把v[i][j](即第i个时间时已经睡了j个单位时间的补充体力值)作为价值,
状态则是f[i][j]表示在第i个时间点已经睡了j个单位时间的最大值。
状态转移方程就和分组背包差不多,但是这个里面的变量值的范围有点绕,在这几乎绕了两个小时,精力还是不够集中啊~
首先我们可以确定最外层的循环为i[1--n]
中间那层则是j[min(i,m)--0]随便是不是逆序,理由就不解释了吧。
最里层的话就是有由k和j确定的 g[min(k,j)--0]这个顺序可以是正向的,只是后面的边界值有所改变而已,另外为什么是min(k,j)了
因为boss在k时间后会发现他在睡觉,所以只能在某个时间点前睡k个单位时间(包括该时间点),//这个地方wa了几次,后来才发现的
posted on 2011-07-21 12:04 sleeper_qp 阅读(213) 评论(0) 编辑 收藏 举报