强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan
动态规划(dynamic programming)是求解决策过程最优化的数学方法,把多阶段过程转换为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法。
将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
现在有5个物品,第i个物品的价值为vi,重量为wi,背包的容量为W,其中的参数都为非负数,W=17。求解如何放物品使得背包的总价值最大。假设我们将物品的价值从低到高排好序如下表:
物品编号 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
价值v | 4 | 5 | 10 | 11 | 13 |
重量w | 3 | 4 | 7 | 8 | 9 |
1号物品重量为3,我们先将背包分成从0到17,共18份,当背包容量是0时,物品1无法放入背包,所以最大价值为0,依次类推,当背包的容量为3时,刚好可以将1号物品放入背包,则此时背包中最大价值为4(即为物品1的价值,位置为下表格标红处),背包容量依次增大到17,背包中还是盛放1号物品,所以,将1号物品放入背包的最大价值为4。
I\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
2号物品的重量是4,价值为5,当背包的容量为4时,可以考虑放入物品2或者物品1,因为物品2的价值>物品1的价值,所以将物品2放入背包,此时背包的最大价值为5(如下表格中第三行第一个标红的位置),背包容量逐渐增大,当背包容量为7时,可以将物品1和物品2都放入背包,此时背包内最大价值为9(物品1价值+物品2价值),背包容量递增至17,都是放入物品1和物品2,所以结果是最大价值为9。
I\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
2 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
3号物品的重量为7,价值为10,背包容量为0~6时,最大价值和上一行(表格第三行)相同,当背包容量为7时物品3的价值大于上一行时的价值,需要调整,直至背包容量为10时,背包中可放入物品1和物品3,且两者价值之和大于当前最大价值,需要调整为4+10=14,当背包容量增至14时可以放入物品1、物品2和物品3,且三者价值之和大于当前最大价值,所以调整为4+5+10=19,背包容量达到17时仍然放这三个物品,所以结果为当前最大价值是19.
I\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
2 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
3 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 10 | 10 | 14 | 14 | 14 | 14 | 19 | 19 | 19 | 19 |
4号物品的重量为8,价值为11,在背包容量为0~7时,背包内的最大价值与上一行相同,容量增加到8时可尝试将物品4放入,物品4的价值大于当前最大价值,则条换为11,当背包容量增至11时刻尝试放入物品1和物品4,且价值之和大于当前最大价值,则调整为15,背包容量为12时刻尝试放入物品2和物品4,且价值之和大于当前最大价值,则调整为16,背包容量增至15时可尝试放入物品3和物品4,且价值之和大于当前最大价值,则调整为21,直至背包容量增加至17时一直存放物品3和物品4为最大价值,则结果为当前最大价值是21.
I\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
2 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
3 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 10 | 10 | 14 | 14 | 14 | 14 | 19 | 19 | 19 | 19 |
4 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 11 | 11 | 14 | 15 | 16 | 16 | 19 | 21 | 21 | 21 |
物品5的重量为9,价值为13,则背包容量在0~8时最大价值和上一行相同,背包容量为9时刻考虑放入物品5,且物品5的价值比当前价值要大,所以进行调整,当前最大价值为13,背包容量增至12时刻考虑放入物品1和物品5,且价值之和大于当前最大价值,调整,当前最大价值为17,背包容量为13时,考虑放入物品2和物品5,且价值之和大于当前最大价值,调整,当前最大价值为18,背包容量增至16时考虑放入物品3和物品5,且价值之和大于当前最大价值,调整,当前最大价值为23,背包容量增至17时,考虑放入物品4和物品5,价值之和大于当前最大价值,调整,当前最大价值为24,则结果为当前最大价值为24.
I\W | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
2 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
3 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 10 | 10 | 14 | 14 | 14 | 14 | 19 | 19 | 19 | 19 |
4 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 11 | 11 | 14 | 15 | 16 | 16 | 19 | 21 | 21 | 21 |
5 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 11 | 13 | 14 | 15 | 17 | 18 | 19 | 21 | 23 | 24 |
int **KnasackDP(int n,int* Weights,float* Values){
int i,w; /*物品编号和背包剩余容量*/
/*为二维数组申请空间*/
int** c=(int**)malloc(sizeof(int*)*(n+1));
/*声明一个一维数组存放物品*/
for(i=0;i<=n;i++)
c[i]=(int*)malloc(sizeof(int)*(W+1));
/*初始化二维数组*/
for(w=0;w<=W;w++)
/*0个物品放入背包中,价值为0*/
c[0][w]=0;
for(i=1;i<=n;i++){
/*i个物品放到容量为0的背包中,价值为0*/
c[i][0]=0;
for(w=1;w<=W;w++){
if(Weights[i-1]<=w){ /*背包剩余容量大于物品重量*/
/*将当前物品放入背包的最大价值>不放的最大价值*/
if(Weights[i-1]+c[i-1][w-Weights[i-1]]>c[i-1][w])
{
/*重量为w的背包中放入该物品*/
c[i][w]=Values[i-1]+c[i-1][w-Weights[i-1]];
}
else{
/*重量为w的背包中不放入该物品*/
c[i][w]=c[i-1][w];
}
}
else
/*若物品重量不小于背包容量w,则不放入该物品
c[i][w]=c[i-1][w];
}
}
/*返回最优值*/
return c;
}
void OutputKnapsackDP(int n,int W,int *Weights,float *Values,int **c){
int x[n];
int i;
for(i=n;i>1;i--){
if(c[i][W]==c[i-1][W])
/*物品i没有放入背包,存0*/
x[i-1]=0;
else{
/*物品i放入背包,存1*/
x[i-1]=1;W=W-Weights[i-1];
}
}
if(c[1][W]==0)
/*第一个物品不放入背包*/
x[0]=0;
else
/*第一个物品放入背包*/
x[0]=1;
for(i=0;i
1.每一步的解为当前的最优解
2.存放物品时不存在不完整的情况,只能是将整个物品放入背包或不放入背包两种情况
3.求出最优解够需要构造最优解,判断出都是哪些物品放进了背包