算法设计与分析3-16 最优时间表问题

最优时间表问题

题目介绍

  • 问题描述可以去书上看,这里主要说一下题目什么意思
  • 题目我相信许多人都不能马上理解,至少我没能一下理解,对于算法题,想要理解题目最好的方法就是看样例,我们只要能够根据样例算出来答案,那么对于这道题也就有了更进一步的了解
  • 看一下样例,首先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);//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(){
    
    
    //freopen("input.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    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]) dp[i]=min(dp[i],dp[i+vs[i][j]]+vs[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(){
    
    
    //freopen("input.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    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);//不能超过n
                }
            }
        }
    }
    cout << dp[1];
    return 0;
}

猜你喜欢

转载自blog.csdn.net/roadtohacker/article/details/115113727
今日推荐