贪心策略
贪心选择性质:一个全局最优解可通过做局部最优(贪心)选择来达到。
最优子结构:如果问题的一个最优解包含了其子问题的最优解。
贪心算法与动态规划算法的差异:贪心算法和动态规划算法都要求问题具有最优子结构性质,这是两类算法的一个共同点。但是,对于一个具有最优子结构的问题应该选用贪心算法还是动态规划算法来求解?是不是能用动态规划算法求解的问题也能用贪心算法来求解?下面我们来研究两个经典的组合优化问题,并以此来说明贪心算法与动态规划算法的主要差别。
一、部分背包问题
假定有n个商品,每个商品i的重量为w[i],价值为v[i],现有一个背包,最多能装M的重量。其中(0 <= i < N, 0 < w[i] < M)。
问题:怎样装能使包中装入的商品价值最高(对于每个商品i可以只装该商品的一部分x[i])?
即对w[1]*x[1] + w[2]*x[2] + ... + w[n]*x[n] <= M
当0 <= x[i] <= 1, v[i] > 0, 1 <= i <= n时
使得v[1]*x[1] + v[2]*x[2] + ... + v[n]*x[n]取得最大。
KnapsackMain.c

/**//*
* Copyright@2008,cn.edu.seu.cose
* All rights reserverd.
*
* Author:Greentea
* Date:08.02.11
*/
#include <stdio.h>
#include <stdlib.h>


typedef struct ElemType...{

int *index; /**//*物品编号*/

int length; /**//*物品数*/

float *w; /**//*物品重量*/

float *v; /**//*物品价值*/

float *r; /**//*物品的单位价值*/

float *x; /**//*物品所取量[0, 1]*/
}Elem;

Elem *InitElem(int *index, float *w, float *v, float *r, float *x, int n)

...{
int i;
Elem *e;
e = (Elem *)malloc(n * sizeof(Elem));
e->index = (int *)malloc(n * sizeof(int));
e->w = (float *)malloc(n * sizeof(float));
e->v = (float *)malloc(n * sizeof(float));
e->r = (float *)malloc(n * sizeof(float));
e->x = (float *)malloc(n * sizeof(float));
for(i = 0; i < n; i++)

...{
e->index[i] = index[i];
e->v[i] = v[i];
e->w[i] = w[i];
e->r[i] = v[i] / w[i];
e->x[i] = 0.0;
}
e->length = n;
return e;
}

void FreeElem(Elem **e)

...{
free((*e)->index);
free((*e)->v);
free((*e)->w);
free((*e)->r);
free((*e)->x);
free(*e);
}

void PrintElem(Elem *e)

...{
int i;
for(i = 0; i < e->length; i++)

...{
if(e->x[i] != 0)
printf("%d: %f ", i, e->x[i]);
}
}

/**//*
* 按物品单位价值从大到小排序,由index数组纪录排序后的顺序
*/
void InsertSort(Elem **e)

...{
int i, j, n, keyind;
float key;
float *rr;
n = (*e)->length;
rr = (float *)malloc(n * sizeof(float));
for(i = 0; i < n; i++)

...{
rr[i] = (*e)->r[i];
}
for(j = 1; j < n; j++)

...{
key = rr[j];
keyind = j;
i = j - 1;
while((i >= 0) && (rr[i] < key))

...{
rr[i+1] = rr[i];
(*e)->index[i+1] = (*e)->index[i];
i--;
}
rr[i+1] = key;
(*e)->index[i+1] = keyind;
}
free(rr);
}


/**//*
* c:背包容量
* 依次选取单位重量价值最大的物品
*/
float Knapsack(Elem *e, int c)

...{
int i, n;
float total;
n = e->length;
InsertSort(&e);
total = 0;
for(i = 0; i < n; i++)

...{
e->x[i] = 0;
}
for(i = 0; i < n; i++)

...{
if(e->w[e->index[i]] > c) break;
e->x[e->index[i]] = 1;
total += e->v[e->index[i]];
c -= e->w[e->index[i]];
}
if(i < n)

...{
e->x[e->index[i]] = c / e->w[e->index[i]];
total += e->x[e->index[i]] * e->v[e->index[i]];
}
return total;
}

int main(int argc, char **argv)

...{

float w[] = ...{35, 30, 60, 50, 40, 10, 25};

float v[] = ...{10, 40, 30, 50, 35, 40, 30};

float r[] = ...{0, 0, 0, 0, 0, 0, 0};

float x[] = ...{0, 0, 0, 0, 0, 0, 0};

int index[] = ...{0, 1, 2, 3, 4, 5, 6};
int n = 7;
Elem *elem;
int c = 150;
elem = InitElem(index, w, v, r, x, n);
printf("Total Value:%f ", Knapsack(elem, c));
PrintElem(elem);
FreeElem(&elem);
return 0;
}
0/1背包问题
问题同上,只是每次取时,x[i]只能取值0或1。
贪心选择性质:一个全局最优解可通过做局部最优(贪心)选择来达到。
最优子结构:如果问题的一个最优解包含了其子问题的最优解。
贪心算法与动态规划算法的差异:贪心算法和动态规划算法都要求问题具有最优子结构性质,这是两类算法的一个共同点。但是,对于一个具有最优子结构的问题应该选用贪心算法还是动态规划算法来求解?是不是能用动态规划算法求解的问题也能用贪心算法来求解?下面我们来研究两个经典的组合优化问题,并以此来说明贪心算法与动态规划算法的主要差别。
一、部分背包问题
假定有n个商品,每个商品i的重量为w[i],价值为v[i],现有一个背包,最多能装M的重量。其中(0 <= i < N, 0 < w[i] < M)。
问题:怎样装能使包中装入的商品价值最高(对于每个商品i可以只装该商品的一部分x[i])?
即对w[1]*x[1] + w[2]*x[2] + ... + w[n]*x[n] <= M
当0 <= x[i] <= 1, v[i] > 0, 1 <= i <= n时
使得v[1]*x[1] + v[2]*x[2] + ... + v[n]*x[n]取得最大。
KnapsackMain.c

/**//*
* Copyright@2008,cn.edu.seu.cose
* All rights reserverd.
*
* Author:Greentea
* Date:08.02.11
*/
#include <stdio.h>
#include <stdlib.h>

typedef struct ElemType...{
int *index; /**//*物品编号*/
int length; /**//*物品数*/
float *w; /**//*物品重量*/
float *v; /**//*物品价值*/
float *r; /**//*物品的单位价值*/
float *x; /**//*物品所取量[0, 1]*/
}Elem;
Elem *InitElem(int *index, float *w, float *v, float *r, float *x, int n)
...{
int i;
Elem *e;
e = (Elem *)malloc(n * sizeof(Elem));
e->index = (int *)malloc(n * sizeof(int));
e->w = (float *)malloc(n * sizeof(float));
e->v = (float *)malloc(n * sizeof(float));
e->r = (float *)malloc(n * sizeof(float));
e->x = (float *)malloc(n * sizeof(float));
for(i = 0; i < n; i++)
...{
e->index[i] = index[i];
e->v[i] = v[i];
e->w[i] = w[i];
e->r[i] = v[i] / w[i];
e->x[i] = 0.0;
}
e->length = n;
return e;
}
void FreeElem(Elem **e)
...{
free((*e)->index);
free((*e)->v);
free((*e)->w);
free((*e)->r);
free((*e)->x);
free(*e);
}
void PrintElem(Elem *e)
...{
int i;
for(i = 0; i < e->length; i++)
...{
if(e->x[i] != 0)
printf("%d: %f ", i, e->x[i]);
}
}
/**//*
* 按物品单位价值从大到小排序,由index数组纪录排序后的顺序
*/
void InsertSort(Elem **e)
...{
int i, j, n, keyind;
float key;
float *rr;
n = (*e)->length;
rr = (float *)malloc(n * sizeof(float));
for(i = 0; i < n; i++)
...{
rr[i] = (*e)->r[i];
}
for(j = 1; j < n; j++)
...{
key = rr[j];
keyind = j;
i = j - 1;
while((i >= 0) && (rr[i] < key))
...{
rr[i+1] = rr[i];
(*e)->index[i+1] = (*e)->index[i];
i--;
}
rr[i+1] = key;
(*e)->index[i+1] = keyind;
}
free(rr);
}

/**//*
* c:背包容量
* 依次选取单位重量价值最大的物品
*/
float Knapsack(Elem *e, int c)
...{
int i, n;
float total;
n = e->length;
InsertSort(&e);
total = 0;
for(i = 0; i < n; i++)
...{
e->x[i] = 0;
}
for(i = 0; i < n; i++)
...{
if(e->w[e->index[i]] > c) break;
e->x[e->index[i]] = 1;
total += e->v[e->index[i]];
c -= e->w[e->index[i]];
}
if(i < n)
...{
e->x[e->index[i]] = c / e->w[e->index[i]];
total += e->x[e->index[i]] * e->v[e->index[i]];
}
return total;
}
int main(int argc, char **argv)
...{
float w[] = ...{35, 30, 60, 50, 40, 10, 25};
float v[] = ...{10, 40, 30, 50, 35, 40, 30};
float r[] = ...{0, 0, 0, 0, 0, 0, 0};
float x[] = ...{0, 0, 0, 0, 0, 0, 0};
int index[] = ...{0, 1, 2, 3, 4, 5, 6};
int n = 7;
Elem *elem;
int c = 150;
elem = InitElem(index, w, v, r, x, n);
printf("Total Value:%f ", Knapsack(elem, c));
PrintElem(elem);
FreeElem(&elem);
return 0;
}
0/1背包问题
问题同上,只是每次取时,x[i]只能取值0或1。
本文探讨了贪心算法的贪心选择性质和最优子结构,并通过部分背包问题进行实例解析。通过按物品单位价值从大到小排序,依次选取单位价值最大的物品装入背包,实现背包最大价值。代码实现展示了如何运用贪心策略解决部分背包问题。
&spm=1001.2101.3001.5002&articleId=2088190&d=1&t=3&u=375e90f6e40d487aa4bf93cf29ab0dfd)
8444

被折叠的 条评论
为什么被折叠?



