题解 P2904 【[USACO08MAR]跨河River Crossing】

Ezio_0420

2018-01-09 18:55:38

Solution

# 玄学(蒟蒻)背包(内存优化) ## 边读入边处理加省一个数组(只需一个dp【】) 其实状态转移方程前几位也都写了,如果我们定义dp[i]为i头奶牛过河所需最短时间,定义time[i]数组为前i个奶牛过河所用的时间,那么自然得到f[j]=min(f[j],f[j-i]+time[j-i]+m) ------------ 以上是正常思路,那么我们的循环是这个样子 ```cpp for (int i=1;i<=n;i++){ cin>>t; time[i]=time[i-1]t; } for (int i=1;i<=n;i++) for (int j=i;j<=n;j++){ dp[j]=min(dp[j],dp[j-i]+time[i]+m); } ``` ,接下来是蒟蒻的特色!重点来了!!(内存优化) 我们会发现,对于第二个循环中的内层循环,我们用到了time[i]来保存前i头奶牛过河时间,而此时外层循环正在枚举每一个i;所以说此时不会用到比time[i]下标大的time[]值,所以说可以把第一个循环省去; ```cpp for (int i=1;i<=n;i++){ cin>>t; time[i]=time[i-1]t; for (int j=i;j<=n;j++){ dp[j]=min(dp[j],dp[j-i]+time[i]+m); } } ``` 进一步,我们发现此时连比time[]下标小的time值都不会用到,所以说time数组完全可以省去,变为一个变量,每次加上新读入的没头奶牛的t值! ```cpp #include<iostream> #include<algorithm> #include<cstdio> using namespace std; int n,m,t,time,dp[2501]; int main(){ cin>>n>>m; for(int i = 1;i<=n;i++) dp[i]=100000000; time=m; for (int i=1;i<=n;i++){ scanf("%d",&t); time+=t; for(int j=i;j<=n;j++){ dp[j]=min(dp[j],dp[j-i]+time+m); } } cout<<dp[n]-m; return 0; } 一个小小的优化,希望能帮到大家 ```