动态规划思想
把问题拆分成若干个子问题,类似递归(分治),但是动规多用于处理最优解,有重叠子问题的问题,因为动态规划对于重叠子问题不会反复计算,会创建一张表将之前计算过的子问题答案直接保存,避免了重复计算,加快计算速度
练习1:有8个任务,每个任务完成需要一定的时间,完成之后就会有相应的报酬(图上的红色字段),但是任务有时间点限制,比如第一个任务在1点到4点。。。。任务之间不能并发,那么一个人做那几个任务可以获取到最高的报酬?
这个思想我们就用动态规划,我们对于某一个任务我们采取选与不选,看选的话获取的报酬大还是不选获取的报酬大,我们设定一个表达式OPT(i),表示到第i个任务的最优解。
比如:我们OPT(8)就有两种结果,一种是选择了8号任务,那么他就不能选择6,7任务;若不选择8号,那么最优值就是OPT(7),所以这个问题的递归式就是
选择:vi + OPT(i-x); //i-x是距离i之前最近的一个可以选择的任务,vi表示i任务的报酬
OPT(i)=max {
不选择:OPT(i-1);
我们可以将某一个任务执行的话,他前边最近可以执行的任务号列一个表,以及我们看一下展开图
可以看出,我们将这个展开图中出现了重叠子问题,比如这个OPT(5),那么我们就可以先算出每一个任务对应的OPT,列出这张表,表填完的时候答案也就自然揭晓了(到最后一个任务)。
这就是这道题的思想,那么上代码
#include<iostream>
#include<map>
#include<vector>
using namespace std;
int main()
{
int val[8]={5,1,8,4,6,3,2,4}; //每一个任务的报酬
int arr[8][2]={1,4,3,5,0,6,4,7,3,8,5,9,6,10,8,11}; //存放每一个任务的开始与结束点
vector<int> vec(8); //存储每一个任务距离他最近的前面的可以同时执行的任务下标
int i=0;
int j=0;
for(;i<8;i++)
{
for(j=i-1;j>=0;j--)
{
if(arr[j][1]<=arr[i][0])
{
vec[i]=j;
break;
}
}
if(j<0)
vec[i]=-1;
}
vector<int> sumval(8);
sumval[0]=val[0];
for(i=1;i<8;i++)
{
if(vec[i]!=-1)
sumval[i]=max(sumval[i-1],val[i]+sumval[vec[i]]);
else
sumval[i]=max(sumval[i-1],val[i]);
}
cout<<sumval[7]<<endl;
}
对于递归版当然很好写了
int GetSumVal(int i)
{
if(i==0) return val[0];
else
{
if(vec[i]==-1)
return max(GetSumVal(i-1),GetSumVal(vec[i]));
return max(GetSumVal(i-1),GetSumVal(vec[i])+val[i]);
}
}
int main()
{
cout<<GetSumVal(7)<<endl;
}
以上就是动态规划的大致思想,就是杜绝这种重复的子问题多次计算!!!用表记录,表填完的时候答案也就出来了