ECUST Sleeping at Work
http://202.120.106.94/onlinejudge/problemshow.php?pro_id=406
此题纠结我一天时间,仍然只是理解了大牛的代码,自己却实现的各种错误,现针对大牛代码给出详细解释,若以后有幸作出此题,必给详细解题过程
1 #include <stdio.h>
2 #include <memory.h>
3 int n,m,r;
4 int dp[501][51][51];
5 int a[501];
6 int i,j,k;
7 int main()
8 {
9 int cas;
10 scanf("%d",&cas);
11 while(cas--)
12 {
13 scanf("%d %d %d",&n,&m,&r);
14 for(i=1;i<=n;scanf("%d",&a[i++]));
15 if(n%(r+1)+n/(r+1)*r>=m) //此处是判断能否有足够的休息时间
16 {
17 int ans=-1;
18 memset(dp,-1,sizeof(dp)); //初始化所有时间段为-1
19 dp[0][0][0]=0;
20 for(i=0;i<n;++i) //确定第i分钟
21 {
22 for(j=0;j<=m;++j) //指第i分钟之前包括第i分钟具有的睡眠时间
23 {
24 for(k=0;k<r;++k) //指从第i分钟向前连续睡k分钟,大牛采用的是由前往后推的方式
25 {
26 if(dp[i][j][k]==-1) continue; //当前者为-1时说明该点不具有值
27 if(j<m)
28 dp[i+1][j+1][k+1]=dp[i][j][k]+(k+1)*a[i+1];//这是连续时间的效应
29 if(dp[i+1][j][0]<dp[i][j][k])
30 dp[i+1][j][0]=dp[i][j][k]; //这个0十分重要,因为当你手算推导时会发现,最终会回到某一分钟的0这个点,它代表前面具有j个睡眠时间时的最大值
31 }
32 if(dp[i+1][j][0]<dp[i][j][k])
33 dp[i+1][j][0]=dp[i][j][k];//不要忘记0要统计i下j分钟下的最大值
34 }
35 }
36 for(i=0;i<=r;++i)
37 {
38 if(ans<dp[n][m][i])
39 ans=dp[n][m][i];
40 } //最后只要求解在n分钟下有m分钟睡眠时间时的最大值
41 printf("%d\n",ans);
42 }
43 else
44 printf("impossible\n");
45 }
46 return 0;
47 }