贪心算法

完成中...

Posted by Pele on May 5, 2022

贪心溯算法并不从整体最优上加以考虑,所作的选择只是在某种意义上的局部最优选择 –> 希望得到整体最优

活动安排问题

/*
 * Params:
 * 		1. int n -> 活动个数
 * 		2. T s[] -> Start Time Array 
 * 		3. T f[] -> Finish Time Array 
 * 		4. bool A[] -> 选择的活动 
 * Return: void
 * Remark: 输入的数组按照阶*结束时间*非减排序,排序时间复杂度O(nlogn)
 */
template <class T>
void GreedySelector(int n, T s[], T f[], bool A[])
{
	A[1] = true;  //先选中第一个活动
	int current = 1;	  // j 表示当前选中的结束时间最晚的活动
	for (int i = 2; i <= n; i++) {
		if(s[i] > f[current]) {  // 判断活动的起始时间是否不早于当前活动
			A[i] = true;
			current = i;
		} 
		else A[i] = false;
	}
}

贪心算法的基本要素

贪心选择性质

贪心选择性质是指,所求问题的整体最优解可以通过一系列局部最优的选择(即贪心选择)达到

最优子结构性质

当一个问题的最优解包含其最解时,称此问题具有最优子结构性质

若A是关于E的活动安排问题包含活动1的一个最优解,则相容活动集合A’=A-{1}是对$E’={i\in E’:s_i \ge f_i}$的活动安排的一个最优解

贪心算法与动态规划算法的差异

贪心算法和动态规划算法都要求问题具有最优子结构性质,这是两类算法的一个共同点.

对比 0-1背包🎒问题和背包问题

/*
 * Params:
 * 		1. int n -> 物品个数
 * 		2. float M -> 背包容量
 * 		3. float v[] -> 物品价值数组
 * 		4. float w[] -> 物品重量数组
 * 		5. float [] -> 是否选中物品
 * Return: void
 * Remark: 开始选择前按照按照物品的单位价值v_i/w_i降序排序
 */
void Knapsack(int n, float M, float v[], float w[], float x[]){
	Sort(n,v,w);
	int i;
	for(i=1;i <= n; i++) x[i] = 0;
	float c = M;  // c为剩余容量
	for( i=1 ; i <= n ; i++) {
		if(w[i]>c) break;
		x[i] = 1;
		c -= w[i];
	}
	if(i <= n)  //如果有物品未装入背包
		x[i] = c/w[i];
}

单源最短路径(Dijkstra算法)