题目介绍
问题描述可以去书上看,这里主要说一下题目什么意思 题目我相信许多人都不能马上理解,至少我没能一下理解,对于算法题,想要理解题目最好的方法就是看样例,我们只要能够根据样例算出来答案,那么对于这道题也就有了更进一步的了解 看一下样例,首先15的意思是仪器的工作时间,那也就是说他这仪器就工作这么长时间,那这最短维修时间最长也就这么长;下面是6个维修程序的起始时间和持续时间,这里可以画一个线段图,方便理解。第一个和第二个起始时间一样,维修时间不同,那是应该选择第一个还是第二个呢?题目描述里面有这么一句话,维修程序必须从头开始,不能从中间插入,也就是说,如果选择第二个,那么1-6这个时间段只能有这一个程序在运行,其他程序等着,那这下一个4开始持续11个时间单位的程序就没机会运行了 还有一个关键点,有这么一句话,一旦启动维修程序,一起必须进入维修程序,也就是说这精密仪器不能等着,如果它没在运行,这时候来了一个程序就必须运行,也就是说如果选择第一个程序,那么第三个4开始持续11的程序就必须要选择了 还有一点,如果有某个程序没完成,精密仪器工作时间结束了该怎么办呢?我认为这时候应该以精密仪器工作结束的时间作为时间终止点 所以这个样例实际工作的程序应该是第2、4个
解法
搜索
既然这道题放在了动态规划这一节那就应该是采用动态规划思想,但也可以搜索,而且是从前往后搜索,对于每个时间点进行搜索,如果当前时间点有程序开始,那么开始搜索以他开始的情况,建立搜索树,这个思路应该不难,程序如下
# include <iostream>
# include <vector>
using namespace std;
const int MAXN = 2e5 + 100 ;
int dp[ MAXN] ;
vector< int > vs[ MAXN] ;
int ans = 0x3f3f3f3f ;
void dfs ( int m, int n, int now) {
if ( m >= n) {
ans = min ( ans, now) ;
ans = min ( ans, n) ;
return ;
}
int len = vs[ m] . size ( ) ;
if ( len != 0 ) {
for ( int i= 0 ; i< len; i++ ) {
dfs ( m + vs[ m] [ i] , n, now + vs[ m] [ i] ) ;
}
}
else dfs ( m + 1 , n, now) ;
}
int main ( ) {
int n, k, x, y;
cin >> n >> k;
for ( int i= 0 ; i< k; i++ ) {
cin >> x >> y;
vs[ x] . emplace_back ( y) ;
}
dfs ( 1 , n, 0 ) ;
cout << ans;
return 0 ;
}
DP
动态规划从前往后不好处理,因为没有最优子结构的性质,需要从后往前考虑,因为后面的都考虑过了,起始时间相同,只需要取耗费时间最短的那一个就可以,有点类似于贪心的活动安排问题 最后一个点不需要考虑从他之前考虑即可 如果设vs[i][j]是第i个时间的第j个程序需要的时间,那么状态转移方程为
d
p
[
i
]
=
m
i
n
(
d
p
[
i
]
,
d
p
[
i
+
v
s
[
i
]
[
j
]
]
+
v
s
[
i
]
[
j
]
)
dp[i]=min(dp[i],dp[i+vs[i][j]]+vs[i][j])
d p [ i ] = m i n ( d p [ i ] , d p [ i + v s [ i ] [ j ] ] + v s [ i ] [ j ] )
# include <iostream>
# include <vector>
# include <cstring>
using namespace std;
const int MAXN = 2e5 + 100 ;
vector< int > vs[ MAXN] ;
int dp[ MAXN] ;
int main ( ) {
int n, k, x, y;
cin >> n >> k;
for ( int i= 0 ; i< k; i++ ) {
cin >> x >> y;
vs[ x] . emplace_back ( y) ;
}
memset ( dp, 0x3f , sizeof dp) ;
dp[ n] = 0 ;
for ( int i= n- 1 ; i> 0 ; i-- ) {
int len = vs[ i] . size ( ) ;
if ( len == 0 ) dp[ i] = dp[ i + 1 ] ;
else {
for ( int j= 0 ; j< len; j++ ) {
int t = dp[ i + vs[ i] [ j] ] + vs[ i] [ j] ;
if ( t <= n) {
dp[ i] = min ( dp[ i] , dp[ i + vs[ i] [ j] ] + vs[ i] [ j] ) ;
} else {
dp[ i] = min ( dp[ i] , n) ;
}
}
}
}
cout << dp[ 1 ] ;
return 0 ;
}