[USACO2009 OPEN] 滑雪课 Ski Lessons
看到题目就觉得这是动规但一直没想到如何状态转移……看了别人的题解之后才有一些想法
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
最后吧分享一句关于动规挺有感触的一句话……
除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解
(新人第一次发帖,多多指教)