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,给我直接整蒙了。

posted @ 2022-02-27 00:17  tyrii  阅读(116)  评论(0)    收藏  举报