[USACO2009 OPEN] 滑雪课 Ski Lessons

洛谷P2948

 

看到题目就觉得这是动规但一直没想到如何状态转移……看了别人的题解之后才有一些想法

f[i][j]:前i单位时间能力值为j可以滑的最多次数

lessons[i][j]:结束时间为i,获得能力为j的时长最短的课程的开始时间

ski[i]:能力值为i可以滑的时间最短的坡的时长

d[i]表示前i时长最多可以滑的坡数

 

几个状态转移方程:

喝可可:f[i][j]=max(f[i][j],f[i-1][j])

滑雪:f[i][j]=max(f[i][j],f[i-ski[j]][j]+1)

上课:f[i][j]=max(f[i][j],d[lessons[i-1][j]])

 

随手贴个代码:

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 int lessons[10001][101],ski[111],f[10001][101],d[10001];
 6 //lessons[i][j]表示结束时间为i,能力为j的课程的最晚开始时间 
 7 //ski[i]表示能力值为i可以滑的时间最短的坡的时长 
 8 //f[i][j]表示前i时长能力值为j最多可以滑的坡数 
 9 //d[i]表示前i时长最多可以滑的坡数 
10 int t,s,n;
11 int main()
12 {
13     scanf("%d%d%d",&t,&s,&n);
14     for(int i=1;i<=s;i++)//初始化lessons[][] 
15     {
16         int m,l,a;
17         scanf("%d%d%d",&m,&l,&a);
18         lessons[l+m-1][a]=max(lessons[l+m-1][a],m);
19     }
20     for(int i=1;i<=n;i++)//初始化ski[] 
21     {
22         int c,d;
23         scanf("%d%d",&c,&d);
24         for(int j=c;j<=100;j++)
25             if(!ski[j]||ski[j]>d)
26                 ski[j]=d;
27     }
28     for(int i=0;i<=t;i++)
29         for(int j=0;j<=100;j++)
30             f[i][j]=-1000000;
31     f[0][1]=0;
32     for(int i=1;i<=t;i++)
33     {
34         for(int j=1;j<=5;j++)
35         {
36             f[i][j]=max(f[i][j],f[i-1][j]);//喝可可 
37             if(ski[j]&&i>=ski[j])//滑雪 
38                 f[i][j]=max(f[i][j],f[i-ski[j]][j]+1);
39             if(lessons[i-1][j])//上课 
40                 f[i][j]=max(f[i][j],d[lessons[i-1][j]]);
41             d[i]=max(d[i],f[i][j]);
42         }
43     }
44     printf("%d\n",d[t]);
45     return 0;
46 }

注意两个问题:

1、初始化:f[0][1]=0(初始化能力为1),其余都为负无穷!

2、状态转移方程没有f[i][j]=max(f[i][j],f[i][j-1)!

第一次写的时候因为这两个问题WA了……但自己也没想出来为什么……如果有神犇理解的话敬请指教w  

 

最后吧分享一句关于动规挺有感触的一句话……

除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解

(新人第一次发帖,多多指教)

posted @ 2018-08-14 17:32  李昊哲  阅读(396)  评论(0编辑  收藏  举报