C. Road Optimization-codeforces-区间dp
C. Road Optimization
题目大意:
一条直路上有n块路牌,在si处有值为hi的路牌。hi表示在这块路牌之后直到下一块路牌前,车子开一千米最快需要hi的时间(hi h/km)。现在能拿走k块路牌,问从0到m,最少需要花费多少时间。
思路和代码:
很经典的区间dp吧。但是我卡了一个寒假
dpij表示现在走到了第i块路牌并且拿掉了j块所需要的最短时间。状态转移方程如下:
$$
dp_{i,j} = min(dp_{i,j},dp_{prei,j-(i-prei-1)}+h_{prei} * (s_i-s_{prei} ))
$$
什么意思呢,就是走到第i个路牌,那最多我们可以把i-k到i-1的k块路牌全拿掉。而这就是prei。当然,若要从prei状态转移到i就意味着在prei后面拿走了i-prei-1块路牌,所以在1到prei中拿走了j-(i-prei-1)个路牌。
最后注意一下边界即可。
void solve(){
cin >> n >> m >> k ;
vct<ll> s(n + 1 , 0) ;
vct<ll> h(n + 1 , 0) ;
rep(i , 1 , n) cin >> s[i] ;
rep(i , 1 , n) cin >> h[i] ;
s.pb(m) ;
h.pb(0) ;
vct<vct<ll> > dp(n + 2 , vct<ll> (k + 2 , INF)) ;
dp[0][0] = 0 ;
rep(i , 1 , n + 1) dp[i][0] = dp[i - 1][0] + h[i - 1] * (s[i] - s[i - 1]) ;
rep(i , 1 , n + 1)
rep(j , 0 , k){//一共拿走了j个
if(j > i - 2) break ;//只有i-2个能拿走,怎么可能拿比i-2多的呢
rep(prei , i - j - 1 , i - 1){
if(prei >= 0 && j - i + prei + 1 >= 0)
dp[i][j] = min(dp[i][j] , dp[prei][j - (i - prei - 1)] + h[prei] * (s[i] - s[prei])) ;
}
}
ll ans = INF ;
rep(i , 0 , k) ans = min(ans , dp[n + 1][i]) ;
cout << ans << "\n" ;
}//code_by_tyrii
上述代码中对dp的第0列做了额外的初始化,这是因为j<=i-2的条件,使得i-j-1>=1,即prei到不了0 。所以需要对第零列做初始化。
小结:
要格外注意初始条件,状态转移。
在做状态转移的时候不能遗漏情况。
吐槽一下,tourist的代码里写的是oldj,给我直接整蒙了。

浙公网安备 33010602011771号