最优批处理问题-动态规划

题目介绍

题目摘选自《计算机算法设计与分析(第5版)》,作者是王晓东,题目如下
在这里插入图片描述

分析

这道题也可以运用动态规划的算法解决,乍一看好像看不出来有什么最优子结构的性质,这道题目我们不能把它看作是最长升序子序列那样,一个一个元素拿出来分解成若干个含有重复的子问题,这种拆分的办法这个问题不适用。

这道题我们需要以分组为单位进行拆分,比如说题目给的例子{1,2}{3}{4,5},这是原问题的最优解,我们把第一组拆分出来,那么剩下的{3}{4,5}这两组实际上就是子问题1:3,4,5这三个作业中的最优解,而如果我们只是单纯的把1拿出来,那么剩下的{2}{3}{4,5}可不一定就是子问题2:2,3,4,5中的最优解了。我们弄清楚这个问题之后,就可以仔细分析,写出状态转移方程了。

假如说我们以作业2为例,前面的子问题1的最优解为{3}{4,5},假设这个子结构的花销为dp[2](数组从0开始),那么我们有很多种选择方法,比如{2}{3}{4,5},那么这个对应的值就是dp[2],也就是2本身一组的自己开销,加上{3}{4,5}的花销(注意这里的花销是{3}{4,5}在第二个作业处理的时间内造成的花销,因为题目要求,第二个作业处理结束之后的时间内的开销就是dp[2])。

再举一个例子,比如我们选择{2,3}{4,5}的分组方式,也就是我们选择的切分点在第三个元素,那么就是dp[3](注意这里是第四个元素的dp值),也就对应了{4,5}在{2,3}组处理之后的时间段内造成的开销,我们还要加上数组{2,3}和数组{4,5}在处理{2,3}这段时间内造成的开销。

对于所有的切分方式,我们都要进行计算,要找到一个造成最终的开销最小的点,这个点就是子问题的答案。

所以状态转移方程为:
dp[i] = min(dp[i],dp[j]+(S+ti+ti+1+…+tj-1)*(fi+fi=1+…+fn-1))
后面的开销之所以要把从i往后的开销都要算上的原因在上面已经具体说明。

代码

//program:Optimal batch problem
//author:William.L
//version:v 1.0

#include <iostream>
#include <fstream>
#define MAXN 1000000000
using namespace std;
int my_min(int a,int b){
    return (a < b) ? a : b;
}

int my_accumulate(int* src,int str,int ends){
    if (str > ends){
        return -1;
    }
    int sum = 0;
    for (int i = str;i <= ends; i++){
        sum += src[i];
    }
    return sum;
}

int main(){
    int num;//works number.
    ifstream in("test file.txt");
    int S;//the machine's start time.
    in >> num >> S;
    int t[num+1],f[num+1];//t means time , f means cost per time.
    for (int i = 0;i < num; i++){
        in >> t[i] >> f[i];
    }
    t[num] = f[num] = 0;//add one after the last work to calculate.
    in.close();
    int dp[num+1];//the array dp[i] means the lowest cost of the array start with the i'th work.
    for (int i = 0;i < num; i++){
        dp[i] = MAXN;
    }
    dp[num] = 0;//the the after the last is 0
    for (int i = num-1; i >= 0; i--){
        for(int j = i + 1; j <= num; j++){
            dp[i] = my_min(dp[i],dp[j]+ ((S + my_accumulate(t,i,j-1)) * my_accumulate(f,i,num-1) ) );
            //This is the most important step, find the good position to cut the array(point j)
            //the number after j use the best answer of from j to n-1
            //the number before j, put the works from i to j-1 together.
        }
    }
    ofstream out("test file.txt",ios::app);
    out << dp[0] << endl;
    out.close();
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值