贪心算法逐步优化、解决背包问题

五大算法思想:
    一    贪心算法/贪婪算法
        A星寻路  
        大问题 归纳成小问题 然后迭代,每次迭代都是解决小问题,经过无数次迭代后解决大问题
        背包问题    最佳路径
        能且只能做当前看来最佳的选择 如此反复 直至最终得到最优解
        缺陷:
            并非一定能得到整体最优解
            每一步都是局部最优        
        花的时间一般比较少,八九不离十(整体并非最优,但也不差)
        贪心算法准则:最值思想(最大 最小)

        背包问题:
            给定N种物品   一个背包
            每个物品有其价值和体积

            求  背包能装下的最具价值的解

            总共有 n 元,有 m 种商品,每种商品有它的价值和价格

            求  购买价值最高的解
            具体如何解决:

                   对整个背包来说可以放很多种物品
                   对每一种物品来说     第 i 个  只有两种 (装和不装)
            先把单位体积最高价值的放进去,再一个个放,每放一次判断一次   把放很多个 变成 放还是不放
        求最短路径:迪杰斯卡拉算法   求 A 点到 B 点的最佳路径
            某个点到终点的最短路径
            无限覆盖   每次的访问路线都有很多种选择,每次把价值低的选择(路径长度比较大的)去掉,只考虑价值高的选择(路径长度比较小的)
    二    分治思想 
        二分查找  归并排序 快排 23树
    三    动态规划
    四    动态回溯
    五    分支定界
例子:
                      9   
                 4       7
             5       3      1
         2      4       4      1
    7       5       3      2      4

    7       5       3      2      4

    9       9       7      5

   14     12      8

   18     19

   28

求从 顶 到 底 的最大路径 和
9        7        3        4        5 最大   和为 28

怎么用贪心算法的思想去算?
思路一:爆破法 递归 每一种可能都算一下  最终记录最大的

用递归的方式从上到下,每一步找最大的,最终把 值 返回

中间的每一步怎么计算?

1.计算 9 + 4 和 9 + 7 哪个更大,返回大的那个

2.计算 4 + 5 和 4 + 3 和 7 + 3 和 7 + 1 哪个更大

3.继续递归计算

4.最终返回最大的那一个

注意:

如果越界了,当前位置就是最后一个位置,如果没有越界就把大的那个加上

每次递归下面的两个都是 i + 1,j 不变 和 i + 1,j+1

存在浪费的情况

省略掉一些不必要的步骤:

在 Step1 中已经知道 7 + 2 == 9 > 2 + 5 == 7,但是依旧计算了一次 2 + 5 == 7,每个分支都计算了一遍,Step2 对此情况做优化,算过的部分不再计算

准备一个临时的数组做存储

 代码实现

#include <stdio.h>

//5行5列的数组
#define NUM  5
int arr[NUM][NUM] = { 0 };

//记录最大路径和
int count = 0;

//临时数组  用来记录过程中的数据
int maxArr[NUM][NUM] = { 0 };

//初始化数据
void initArr();
//返回ab中大的那个-> 封装函数针对其他类型的比较
int Max(int a, int b);

//获取最大的 行->外层循环 列->内层循环
int getMax(int i, int j);

int main(){
	initArr();
	int num;
	num = getMax(0, 0);

	printf("%d,%d\n", num,count);

	while (1);
	return 0;
}
void initArr(){
	arr[0][0] = 9;
	arr[1][0] = 4; arr[1][1] = 7;
	arr[2][0] = 5; arr[2][1] = 3; arr[2][2] = 1;
	arr[3][0] = 2; arr[3][1] = 4; arr[3][2] = 4; arr[3][3] = 1;
	arr[4][0] = 7; arr[4][1] = 5; arr[4][2] = 3; arr[4][3] = 2; arr[4][4] = 4;

	for (int i = 0; i < NUM; i++){
		for (int j = 0; j < NUM; j++){
			maxArr[i][j] = -1;    //临时数组初始化为-1-> -1说明这个位置上的点没有用过
		}
	}
}
#if 1
int getMax(int i, int j){
	//step 4: 在step3的基础上优化临时数组 并不需要太大的临时数组 第2层的数据可以直接覆盖第1层
	int temp[NUM];
	//先给最下面一层赋值
	for (int i = 0; i < NUM; i++) {
		temp[i] = arr[NUM - 1][i];
	}
	//然后循环计算,一层层往上赋值
	for (int i = NUM - 2; i >= 0; i--){//从下往上
		for (int j = 0; j <= i; j++){//从左往右
			temp[j] = arr[i][j] + Max(temp[j], temp[j + 1]);
		}
	}
	//最终 temp[0]就是我们需要的结果
	return temp[0];
}
#endif

#if 0
int getMax(int i, int j){
	//step 3: 在step2的基础上把递归变成循环 7 5 3 2 4
	//先给最下面一层赋值
	for (int i = 0; i < NUM; i++) {
		maxArr[NUM - 1][i] = arr[NUM - 1][i];
	}
	//然后循环计算,一层层往上赋值
	for (int i = NUM - 2; i >= 0; i--){//从下往上
		for (int j = 0; j <= i; j++){//从左往右
    //加上相邻两个中间大的那一个
			maxArr[i][j] = arr[i][j] + Max(maxArr[i + 1][j], maxArr[i + 1][j + 1]); 
		}
	}
	//最终 maxArr[0][0]就是我们需要的结果
	return maxArr[0][0];              //28 15
}
#endif
#if 0
int getMax(int i, int j){
	//step 2: step1有一些无意义的递归 可以省略  之前递归计算出的结果 直接存储  直接使用 不再算了
	if (maxArr[i][j] != -1) return maxArr[i][j];    //一开始都是-1不会返回 后面不等于-1 直接返回对应位置的值
	count++;
	if (NUM == i){//从最后一行开始赋值
		maxArr[i][j] = arr[i][j];
	}
	else{//递归
		int n = getMax(i + 1, j);
		int m = getMax(i + 1, j + 1);
		maxArr[i][j] = arr[i][j] + Max(n, m);
	}
	return maxArr[i][j];               //28 15
}
#endif
#if 0
int getMax(int i, int j){
	
	//step 1: 递归方式    每一步都计算
	if (NUM == i) return arr[i][j];    //越界就结束-> 返回当前位置

	int n = getMax(i + 1, j);          //左边的分支
	int m = getMax(i + 1, j + 1);      //右边的分支

	printf("i:%d,j:%d,n:%d,m:%d,arr[%d][%d]:%d\n",
		i, j, n, m, i, j, arr[i][j]);
	count++;
	return arr[i][j] + Max(n, m);      //返回当前位置加上n和m中间比较大的那个 28 31
}
#endif
//返回ab中大的那个
int Max(int a, int b){
	return ((a > b) ? a : b);
}

贪心算法解决背包问题

先找最大价值的物品,一直存储,直到放不下

#include <stdio.h>
/*
	有N样物品  和一个容量为V的背包
	每种物品的体积w和价值c如下
	N:5          V:20
	A	B	C	D	E
w:  3	5	6	7	9
c:	2	8	7	4	1
	求背包中价值最大的情况:32
*/

//容量
#define V  20
//体积
#define N  5

//结构体数组
struct WuPin{
	int w, c;
};

WuPin wp[N] = { { 3, 2 }, { 5, 8 }, { 6, 7 }, { 7, 4 }, { 9, 1 } };

//返回ab中大的那个
int Max(int a, int b){
	return ((a > b) ? a : b);
}

int main(){

	int temp[100] = { 0 };

	for (int i = 0; i < N; i++){//种类搭配 5种物品
		//{ 3, 2 }, { 5, 8 }, { 6, 7 }, { 7, 4 }, { 9, 1 }   
		for (int j = wp[i].w; j <= V; j++){//只考虑体积w的变化 j增加的是体积 但temp只存价值
			printf("temp[%d]:%d\n", j, temp[j]);
			temp[j] = Max(temp[j], temp[j - wp[i].w] + wp[i].c);
			printf("i:%d\t j:%d\t temp[%d]:%d\t temp[%d]:%d \t temp[%d] + %d\n", 
				      i,     j,        j,  temp[j],  j - wp[i].w, temp[j - wp[i].w], j - wp[i].w, wp[i].c);
		}
	}

	for (int i = 0; i < 100; i++)
		printf("%d ", temp[i]);
	printf("\n");

	printf("max:%d\n", temp[V]);

	while (1);
	return 0;
}
0 0 0 2 2 8 8 8 10 10 16 16 16 18 18 24 24 24 26 26 32
max:32
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
优化覆盖问题中,贪心算法可以被用来寻找近似最优解。贪心算法是一种简单而有效的算法,它通过每次选择当前最佳的选择来构建问题的解。对于覆盖问题,贪心算法会选择每次选择能够覆盖最多未被覆盖区域的解。 在使用贪心算法优化覆盖问题时,我们需要首先定义问题的目标函数。目标函数可以是最小化覆盖的区域数或者最大化覆盖的区域数,具体取决于问题的要求。 然后,我们将问题的解空间分为两个部分:已覆盖区域和未覆盖区域。我们将开始时的已覆盖区域设为空集,未覆盖区域设为整个问题空间。接着,我们每次选择能够覆盖最多未被覆盖区域的解,并将其添加到已覆盖区域中。 我们重复上述步骤直到所有的区域都被覆盖。最终的解就是覆盖问题的最优解。 需要注意的是,贪心算法并不一定能找到问题的最优解,但它通常能找到一个接近最优解的解。因此,贪心算法是一种实用且高效的近似算法,特别适合用于大规模的覆盖问题。 在MATLAB中实现贪心算法优化覆盖问题可以使用循环和条件判断语句来实现选择最佳解的步骤。同时,我们可以使用向量和矩阵操作来高效地处理问题空间和解空间。 总而言之,贪心算法是一种简单而有效的算法,特别适用于优化覆盖问题。在MATLAB中实现贪心算法可以帮助我们找到近似最优解,解决大规模的覆盖问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuqiuyaq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值