前言

人生如逆旅,我亦是行人。


贪心算法(Greedy Algorithm)

贪心算法(Greedy Algorithm,又称贪婪算法):是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择。


算法思路:

  1. 建立数学模型来描述问题;
  2. 把求解的问题分成若干个子问题;
  3. 对每个子问题进行求解,得到子问题的局部最优解;
  4. 把子问题的解(局部最优解)合成原来问题的解;

贪心算法 是一种对某些求最优解问题的更简单、更迅速的设计技术。贪心算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择,就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解。虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪心算法不要回溯 [2] 。


算法实现:

  1. 从问题的某个初始解出发;
  2. 采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模;
  3. 将所有部分解综合起来,得到问题的最终解;

实例分析


示例一:背包问题

  • 问题描述:

    有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

  • 问题分析:

    1. 目标函数∑pi 求和,最大,使得装入背包中的所有物品 pi 的价值加起来最大;
    2. 约束条件:装入的物品总重量不超过背包容量:∑wi <= M( M=150)
    3. 贪心策略:
      1、选择价值最大的物品。
      2、选择重量最小的物品。
      3、选择单位重量价值最大的物品。

1、值得注意的是,贪心算法并不是完全不可以使用,贪心策略一旦经过证明成立后,它就是一种高效的算法。
2、贪心算法还是很常见的算法之一,这是由于它简单易行,构造贪心策略不是很困难。
3、可惜的是,它需要证明后才能真正运用到题目的算法中。

  • 一般来说,贪心算法的证明围绕着:整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的
  • 对于背包问题中的 3 种贪心策略,都是 无法成立(无法被证明) 的,解释如下:

(1)选取价值最大者

  • W=30
物品 重量 价值
A 28 30
B 12 20
C 12 20

根据策略,首先选取物品A,接下来就无法再选取了,可是,选取B和C一起,则更好。

(2)选取重量最小者:选取重量最小。它的反例与第一种策略的反例差不多。
(3)选取单位重量价值最大者:

  • W=30
物品 重量 价值
A 28 28
B 20 20
C 10 10

根据策略,三种物品单位重量价值一样,程序无法依据现有策略作出判断,如果选择A,则答案错误。但是如果在条件中加一句当遇见单位价值相同的时候,优先装重量小的,这样的问题就可以解决。

  • 代码实现:
#include<iostream>
#include<algorithm>
using namespace std;typedef struct
{/* data */int weight;     //重量int value;      //价值double avg;
}Package;bool compare(Package a, Package b)
{return a.avg > b.avg;
}int main()
{Package *p;int n, m;       //n:物品个数,m:背包容量while (cin >> n >> m)   //当有输入{/* code */p = new Package[n];for (int i = 0; i < n; i++){/* code */cin >> p[i].weight >> p[i].value;       //输入物品的重量和价值p[i].avg = p[i].value / p[i].weight * 1.0;}sort(p, p+n, compare);int maxvalue = 0;for (int i = 0; i < n; i++){/* code */if (m >= p[i].weight){/* code */m = m - p[i].weight;maxvalue = maxvalue + p[i].value;}else{break;}}cout << "最大总价值为:" << maxvalue << endl;}system("pause");return 0;
}
  • 运行结果:
这个算法里面就是采用的贪心第三方案,一般这个方案是成功率最大的。

示例二:活动时间安排问题

  • 问题描述:

    设有 n个活动的集合 E={1,2,…,n},其中每个活动都 要求使用同一资源,如:演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间 si 和一个结束时间 fi ,且 si <fi要求设计程序,使得安排的活动最多。

    (注:活动结束时间从小到大排序)

  • 问题分析:

    活动安排问题要求安排一系列争用某一公共资源的活动。用贪心算法可提供一个简单、漂亮的方法,使尽可能多的活动能兼容的使用公共资源。设有 n 个活动的集合{0,1,2,…,n-1},其中每个活动都要求使用同一资源,如会场等,而在同一时间内只有一个活动能使用这一资源。每个活动 i 都有一个要求使用该资源的起始时间 starti 和一个结束时间 endi ,且 starti < endi。如选择了活动 i,则它在半开时间区间[starti,endi)内占用资源。若区间 [starti,endi) 与区间 [startj,endj) 不相交,称活动 i 与活动 j相容的。也就是说,当 startj ≥ endistarti ≥ endj 时,活动 i 与活动 j 相容。活动安排问题就是在所给的活动集合中选出最多的不相容活动

    活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合,是可以用贪心算法有效求解的很好例子。该问题要求高效地安排一系列争用某一公共资源的活动。贪心算法提供了一个简单、漂亮的方法使得尽可能多的活动能兼容地使用公共资源。

  • 算法设计:

    若被检查的 活动 i 的开始时间 starti 小于最近选择的 活动 j 的结束时间 endj,则不选择 活动 i,否则选择 活动 i 加入集合中。运用该算法解决活动安排问题的效率极高。当输入的活动已按结束时间的非减序排列,算法只需 O(n) 的时间安排 n 个活动,使最多的活动能相容地使用公共资源。如果所给出的活动未按非减序排列,可以用 O(nlogn) 的时间重排。

  • 代码实现:

代码一:

#include<iostream>
#include<algorithm>
using namespace std;struct actime
{/* data */int start,finish;
}act[1002];bool compare(actime a, actime b)
{return a.finish < b.finish;
}int main()
{//n:活动个数,t:与各个活动的起始时间相比较,total:最后的活动的个数int n,t,total;  while (cin >> n)    //活动个数{/* code */for (int i = 0; i < n; i++){/* code */cin >> act[i].start >> act[i].finish;}sort(act, act+n, compare);      //将活动按活动结束时间从小到大排序t = -1;     total = 0;for (int i = 0; i < n; i++)     //循环访问所有活动{/* code */if (t <= act[i].start){/* code */total ++;t = act[i].finish;} }cout << "最多可安排:" << total << "个活动。" << endl;}return 0;
}

代码二:

#include <iostream>
using namespace std;template <class Type>
void GreedySelector(int n, Type s[], Type f[], bool A[]);const int N = 11;int main()
{//将活动时间进行静态数组直接存储//下标从1开始,存储活动开始时间int s[] = {0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12};//下标从1开始,存储活动结束时间int f[] = {0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};bool A[N + 1];cout << "各活动的开始时间,结束时间分别为:" << endl;for (int i = 1; i <= N; i++){cout << "[" << i << "]:" << "(" << s[i] << "," << f[i] << ")" << endl;}GreedySelector(N, s, f, A);cout << "最大相容活动子集为:" << endl;for (int i = 1; i <= N; i++){if (A[i]){cout << "[" << i << "]:" << "(" << s[i] << "," << f[i] << ")" << endl;}}return 0;
}template <class Type>
void GreedySelector(int n, Type s[], Type f[], bool A[])
{A[1] = true;int j = 1; //记录最近一次加入A中的活动for (int i = 2; i <= n; i++) //依次检查活动i是否与当前已选择的活动相容{if (s[i] >= f[j]){A[i] = true;j = i;}else{A[i] = false;}}
}
值得说明一下,虽然贪心算法不是一定可以得到最好的解 ,但是对于这种活动时间的问题,他却得到的总是最优解,这点可以用数学归纳法证明,在这里,体现出来的贪心策略是:每一个活动时间的挑选总是选择最优的,就是刚好匹配的,这样得出的结果也就是最优的了。

示例三:最小生成树(克鲁斯卡尔算法)

在连通网中查找最小生成树的常用方法有两个,分别称为普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法。

克鲁斯卡尔算法 查找最小生成树的方法是:将连通网中所有的边按照权值大小做升序排序,从权值最小的边开始选择,只要此边不和已选择的边一起构成环路,就可以选择它组成最小生成树对于 N 个顶点的连通网,挑选出 N-1 条符合条件的边,这些边组成的生成树就是最小生成树

  • 问题描述:

求一个连通无向图的最小生成树的代价(图边权值为正整数)。

  • 输入:

第一行是一个整数N(1<=N<=20),表示有多少个图需要计算。以下有N个图,第i图的第一行是一个整数M(1<=M<=50),表示图的顶点数,第i图的第2行至1+M行为一个M*M的二维矩阵,其元素ai,j表示图的i顶点和j顶点的连接情况,如果ai,j=0,表示i顶点和j顶点不相连;如果ai,j>0,表示i顶点和j顶点的连接权值。

  • 输出:

每个用例,用一行输出对应图的最小生成树的代价。

  • 样例输入:

1
6
0 6 1 5 0 0
6 0 5 0 3 0
1 5 0 5 6 4
5 0 5 0 0 2
0 3 6 0 0 6
0 0 4 2 6 0

  • 样例输出:

15

  • 问题分析:

    (1)边的选择要求从小到大选择,则开始显然要对边进行升序排序;
    (2)选择的边是否需要,则从判断该边加入后是否构成环;

  • 算法设计:

    (1)对边进行升序排序
    在此采用链式结构,通过插入排序完成。每一结点存放一条边的左右端点序号、权值及后继结点指针;
    (2)边的加入后,是否会构成环
    一开始假定各顶点分别为一组,其组号为端点序号。选择某边后,看其两个端点是否在同一组中,即所在组号是否相同,如果是,表示构成了环,则舍去。 如果两个端点所在的组不同,则表示可以加入,则将该边两端的组合并成同一组。

  • 代码实现:

#include <iostream>
using namespace std;
struct node
{int l;int r;int len;node *next;
};
void insert(node *&h, node *p) //指针插入排序
{node *q = h;while (q->next && q->next->len <= p->len){q = q->next;}p->next = q->next;q->next = p;
}
int main()
{// freopen("001.in","r",stdin);node *h, *p;int n, m, x, temp;int *a;int i, j;int sum;cin >> n;while (n--){sum = 0;cin >> m;a = new int[m + 1];for (i = 1; i <= m; i++){a[i] = i;}h = new node;p = h;p->next = NULL;for (i = 1; i <= m; i++)for (j = 1; j <= m; j++){cin >> x;if (i > j && x != 0){p = new node;p->l = i;p->r = j;p->len = x;p->next = NULL;insert(h, p); //调用插入排序}}p = h->next;while (p){if (a[p->l] != a[p->r]){sum += p->len;temp = a[p->l];for (i = 1; i <= m; i++)if (a[i] == temp){a[i] = a[p->r];}}p = p->next;}//可以测试程序工作是否正常p=h->next;while(p){cout<<p->l<<':';cout<<p->r<<' ';cout<<p->len<<"   ";p=p->next;}cout << sum << endl;}return 0;
}
  • 运行结果:


示例四:(HDU1050)Moving Tables

  • 问题描述:

在一个狭窄的走廊里将桌子从一个房间移动到另一个房间,走廊的宽度 只能允许一个桌子通过。给出 t,表示有 t 组测试数据。再给出 n,表示要移动 n 个桌子。n 下面有 n 行,每行两个数字,表示将桌子从 a 房间移到 b 房间。走廊的分布图如下图所示,每移动一个桌子到达目的地房间需要花10分钟,问移动 n 个桌子所需要的时间。


  • 输入:

3
4
10 20
30 40
50 60
70 80
2
1 3
2 200
3
10 100
20 80
30 50

  • 输出:

10
20
30

  • 解题思路:

    (1)若要移动多个桌子时,所需要经过的走廊没有重合处,即可以同时移动。
    (2)若有一段走廊有 m 个桌子都要经过,一次只能经过一个桌子,则需要 m*10 的时间移动桌子。
    (3)设一个数组,下标值即为房间号。桌子经过房间时,该房间号为下标对应得到数组值加10。最后找到最大的数组值,即为移动完桌子需要的最短时间。

  • 注意:

  1. 可能出发位置比目的地房间大,无论大小,我们都可以看做从小的房间移动到大的房间;
  2. 出发房间为偶数则减一,结束房间为奇数则加一

  • 代码实现:

代码一:

#include <iostream>
#include <algorithm>
using namespace std;struct table
{/* data */int from;  //起点int to;    //终点bool flag; //记录该房间是否被访问过
} moving[205];bool cmp(table a, table b)
{return a.from < b.from;
}int main()
{int T, n; // T:测试实例的个数,n:每次测试下的table个数cin >> T;while (T--){/* code */cin >> n;for (int i = 0; i < n; i++){/* code */cin >> moving[i].from >> moving[i].to;//可能出发位置比目的地房间大,无论大小,我们都可以看做从小的房间移动到大的房间//将起始位置进行交换if (moving[i].from > moving[i].to){int temp = moving[i].from;moving[i].from = moving[i].to;moving[i].to = temp;//swap(moving[i].from, moving[i].to);  交换}//考虑实际情况,出发房间为偶数是减一if (moving[i].from % 2 == 0){moving[i].from--;}//考虑实际情况,结束房间为奇数是加一if (moving[i].to % 2 == 1){moving[i].to++;}//初始化房间未被访问过moving[i].flag = false;}sort(moving, moving + n, cmp); //将所有的table按出发房间从小到大排序bool completion = false;       //是否所有的table移动结束int cnt = -1, priorTo; // priorTo 记录前一个table移动结束的房间while (!completion){completion = true;cnt++;priorTo = 0;//每一轮将可以同时移动的table全部移动完:比如2->5,6->10,因为他们没有共用走廊for (int i = 0; i < n; i++){if (!moving[i].flag && moving[i].from > priorTo){moving[i].flag = true; //标记当前table已经移动完毕priorTo = moving[i].to;completion = false;}}}cout << cnt * 10 << endl;}system("pause");return 0;
}

结果一:


代码二:

#include<iostream>
#include<cstring>
#include<algorithm>using namespace std;int main()
{int T, n, count[410], start, end; // T:测试实例的个数,n:每次测试下的table个数cin >> T;while (T--){/* code */cin >> n;memset(count, 0, sizeof(count));    //初始化函数,将count中的值全部设置为0while (n--){/* code */cin >> start >> end;if (start > end){/* code */// int temp = start;// start = end;// end = temp;swap(start, end);   //进行交换}if (start % 2 == 0)     //出发房间为偶数减一{/* code */start--;}if (end % 2 == 1)       //目的房间为奇数加一{/* code */end++;}for (int i = start; i <= end; i++){/* code */count[i] = count[i] + 10;}}cout << *max_element(count, count+400);}return 0;
}

示例五:线段覆盖(Lines cover)

  • 问题描述:

在一维空间中告诉你N条线段的起始坐标与终止坐标,要求求出这些线段一共覆盖了多大的长度。


  • 解题思路:

    上述的表格中的数据代表10条线段的起始点和终点,对他们的起始点从小到大按顺序排列。

  • 代码编写:

#include<iostream>using namespace std;int main()
{//起始点int start[] = {2,3,4,5,6,7,8,9,10,11};//终点int end[] = {3,5,7,6,9,8,12,10,13,15};int total_len = 1;  //至少的长度为:3-2for (int i = 1, j = 0; i < 10; i++){/* code */if (start[i] >= end[j]){/* code */total_len = total_len + end[i] - start[i];j = i;}else{if (end[i] <= end[j]){/* code */continue;}else{total_len = total_len + end[i] - end[j];j = i;}}}cout << "总共覆盖长度为:" << total_len << endl;system("pause");return 0;
}
  • 结果:


示例六:数字组合问题

  • 问题描述:

    设有N个正整数,现在需要你设计一个程序,使他们连接在一起成为最大的数字。

  • 输入:

3
12 456 342

  • 输出:

45634212

  • 程序要求:

    输入整数N 接下来一行输入N个数字,最后一行输出最大的那个数字。

  • 题目解析:

    (1)看到题目首先想到如何使两个数连接在一起最大,例如 12456 ,连接在一起有两种情况分别为 1245645612 ,显然后者比前者大。
    (2)如果是多个正整数连在一起,我们则需要对元素进行比较,很显然这是一个排序的过程,而且 需要相邻的元素两两比较,由此可以想到我们之前学过的 冒泡排序

// 冒泡排序:
// 1、比较相邻的元素。如果一个比第二个大,就交换他们两个之间的位置
// 2、对每一对相邻元素做同样的操作,执行完毕后,找到第一个最大值
// 3、重复以上的步骤,每次比较次数 -1, 直到不需要比较为止。// 第一轮:找第一个最大数,第二轮:找第二个最大数,…………// 规律:
// 排序的总轮数 = 元素个数 - 1
// 每轮对比次数 = 元素个数 - 排序轮数 - 1#include <iostream>using namespace std;int main()
{// 利用冒泡排序来实现升序序列int arr[9] = {4, 2, 8, 0, 5, 7, 1, 3, 9};cout << "排序前:" << endl;for (int i = 0; i < 9; i++){/* code */cout << arr[i] << " ";}cout << endl;// 开始冒泡排序// 总共排序轮数为:元素个数 - 1for (int i = 0; i < 9 - 1; i++){/* code *///内层对比循环 次数 = 元素个数 - 排序轮数 - 1for (int j = 0; j < 9 - i - 1; j++){/* code :如果第一个数字比第二个数字大,实现交换这两个数字*/if (arr[j] > arr[j + 1]){/* code */int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}//排序后的结果cout << "排序后:" << endl;for (int i = 0; i < 9; i++){/* code */cout << arr[i] << " ";}cout << endl;system("pause");return 0;
}

若有四个数字:456、12、342、78

1、先进行比较 456 和 12,发现 45612 比 12456 更大,此时交换两个数字的位置:12、456、342、78
2、再进行比较 456 和 342,发现 456342 比 342456 更大,再次进行位置的交换:12、342、456、78
3、在进行比较 456 和 78,发现 78456 比 45678 更大,无需进行交换;
4、最后顺序:12 、342 、456 、78

分析到这其实发现要想连接到一起的数字最大,我们其实需要排序的是每个数字的第一位,就像上面的例子,最终每个数字的第一位排序得到: 1, 3 , 4 , 7 ;

综上所述,我们的解题思路:就是在相邻两个正整数连接起来比较大小的基础上再对所有数字冒泡排序,即可完成题目要求

代码实现:

#include <bits/stdc++.h>using namespace std;//num1::12,num2:456
bool Compare(int num1, int num2)
{int count1 = 0, count2 = 0;int nm1 = num1, nm2 = num2;while (nm1){/* code */count1++;   //用来得到 num1 的位数:2nm1 /= 10;}while (nm2){/* code */count2++;   //用来得到 num2 的位数:3 nm2 /= 10;}//pow(a, b):求 a 的 b 次方,这里用作将两个数连接起来进行下一步的比较int a = num1 * pow(10.0, count2) + num2;    //表示组合数:num1 num2:12  * 1000 + 456 = 12456int b = num2 * pow(10.0, count1) + num1;    //表示组合数:num2 num1:456 * 100  + 12  = 45612return a > b ? true : false;    //返回true表示:组合数(num1 num2)大于组合数(num2 num1),反之,则相反
}int main()
{int num;cout << "请输入将输入的数字的个数:";cin >> num;int arr[num];   //int *arr = new int[num];for (int i = 0; i < num; i++){/* code */cin >> arr[i];}for (int i = 0; i < num; i++){/* code */for (int j = 0; j < num - i - 1; j++){/* code *///如果 arr[j] 大于 arr[j+1],则交换,否则,不交换if(Compare(arr[j], arr[j+1])){// int temp = arr[j];// arr[j]   = arr[j+1];// arr[j+1] = arr[j];swap(arr[j], arr[j+1]); //交换}}}cout << "最大组合数为:";for (int i = num - 1; i >= 0; --i){/* code */cout << arr[i];}cout << endl;delete []arr;   //完成之后,删除该数组,节省空间return 0;
}
  • 实验结果:


示例七:找零钱问题

在贪心算法里面最常见的莫过于找零钱的问题了。
  • 问题描述:

对于人民币的面值有1元 、5元 、10元 、20元 、50元 、100元,下面要求设计一个程序,输入找零的钱,输出找钱方案中最少张数的方案,比如: 123元,最少是 1 张100 的,1 张 20 的,3 张 1 元的,一共5张。

  • 问题解析:

    运用的贪心策略是每次选择最大的钱,如果最后超过了,再选择次大的面值,然后次次大的面值,一直到最后与找的钱相等。

  • 代码实现:

#include <bits/stdc++.h>using namespace std;int main()
{int MoneyClass[6] = {100,50,20,10,5,1};     //记录钱的面值int MoneyNum[6] = {0};                      //记录各种面值的数量int money, moneycount = 0, count = 0;       //money:钱数,cout << "请输入你所需要的交换的钱数:";cin >> money;for (int i = 0; i < 6;  ){/* code */if (moneycount + MoneyClass[i] > money)     //如果需要的钱数小于最大的面值{/* code */i++;continue;   //换用更小的面值,继续去判断}moneycount = moneycount + MoneyClass[i];MoneyNum[i] ++;count ++;while (moneycount == money){/* code */break;}}for (int i = 0; i < 6; i++){/* code */if (MoneyNum[i] != 0){/* code */switch (i){case 0:/* code */cout << "面值为100的有:" << MoneyNum[i] << "张" << endl;break;case 1:/* code */cout << "面值为50的有:" << MoneyNum[i] << "张" << endl;break;case 2:/* code */cout << "面值为20的有:" << MoneyNum[i] << "张" << endl;break;case 3:/* code */cout << "面值为10的有:" << MoneyNum[i] << "张" << endl;break;case 4:/* code */cout << "面值为5的有:" << MoneyNum[i] << "张" << endl;break;case 5:/* code */cout << "面值为1的有:" << MoneyNum[i] << "张" << endl;break;}}}cout << "一共需要:" << count << "张纸钱。" << endl;system("pause");return 0;
}
  • 实验结果:


穿插<力扣题>:买卖股票的最佳时机 II

这里再插一道我在力扣刷到的一道题,写的时候刚开始不知道贪心算法,看完其解析之后,发现其用贪心算法写起来十分便捷。然后才开始来自己深入学习一下这个贪婪算法。
  • 问题描述:

    给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

    在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

    返回 你能获得的 最大 利润 。

  • 示例1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。总利润为 4 + 3 = 7 。
  • 示例2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。
  • 提示:

    1. 1 <= prices.length <= 3 * 10^4
    2. 0 <= prices[i] <= 10^4
  • 算法思路:

    贪心算法:对相邻两天的价格进行做比较,做减法。

  • 算法实现(C++):

class Solution {public:int maxProfit(vector<int>& prices) {int len = prices.size();int total = 0;for(int i = 0; i < len - 1;i++){if(prices[i] < prices[i+1])      {total += prices[i+1] - prices[i];}}return total;}
};

<贪心算法>学习及经典实例分析相关推荐

  1. DAY1 贪心算法学习报告

    集训DAY1:贪心算法 学习报告 这天的题还有一道未解决,暂时不会代码实现,由于时间有限(精力是相对无限的),所以留待明天补档. /(课堂笔记) 贪心算法的核心:局部最优得整体最优 证明:数学归纳 微 ...

  2. java贪心算法几个经典例子_经典算法思想5——贪心(greedy algorithm)

    贪心算法,是指在对问题求解时,总是做出再当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是某种意义上的局部最优解. 贪心算法没有固定算法框架,算法设计的关键是贪心策略的选择.必须注 ...

  3. 总结 贪心算法_用经典例题轻松帮你搞定贪心算法

    转自:奶糖猫 贪心算法概念叙述 运用贪心算法求解问题时,会将问题分为若干个子问题,可以将其想象成俄罗斯套娃,利用贪心的原则从内向外依次求出当前子问题的最优解,也就是该算法不会直接从整体考虑问题,而是想 ...

  4. python贪心算法几个经典例子_关于贪心算法的一些探讨、经典问题的解决和三种典型的贪心算法算法(哈弗曼,Kruskal,Prim)的Python实现。...

    贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解. 贪心算法不是对所有问题都能得到整体最优解,关键是 ...

  5. BP神经网络算法基本原理,bp神经网络实例分析

    BP人工神经网络方法 (一)方法原理人工神经网络是由大量的类似人脑神经元的简单处理单元广泛地相互连接而成的复杂的网络系统.理论和实践表明,在信息处理方面,神经网络方法比传统模式识别方法更具有优势. 人 ...

  6. vb中产生随机数经典实例分析

    这个例子算是比较经典的吧,通过分析整个例子从中学习一些新的思维方式. 当然在此之前老师讲过多次这个例子,但是我们大多数同学还都做不出来.原因就是我们没有及时总结,于是今天下午用了一下午的时间总结这个例 ...

  7. Java算法大全_java贪心算法几个经典例子

    Java经典问题算法大全   /*[程序1]   题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?  ...

  8. python希尔排序的优缺点_Python排序搜索基本算法之希尔排序实例分析

    本文实例讲述了Python排序搜索基本算法之希尔排序.分享给大家供大家参考,具体如下: 希尔排序是插入排序的扩展,通过允许非相邻的元素进行交换来提高执行效率.希尔排序最关键的是选择步长,本程序选用Kn ...

  9. RTSP再学习 -- Hi3516A RTSP实例 分析

    上一篇文章,讲到了Hi3516A通过RTSP播放H.265视频流的源码.接下来对源码分析一下. 这里推荐一个工具,参看:日常生活小技巧 -- 文件对比工具 Beyond Compare (1)首先从 ...

最新文章

  1. 机房漏电产生的危害及安全隐患解决方案
  2. 一个“程序员的自我修养”是什么?
  3. Windows 软件安全---注入安全
  4. python 网络页面爬取
  5. Go语言潜力有目共睹,但它的Goroutine机制底层原理你了解吗?
  6. 类和对象编程(二):类访问修饰符
  7. 解决insmod: error inserting 'hello.ko': -1 Invalid module format
  8. dw中创建java程序_新建MainGame.java并创建窗口
  9. 21年最新-李沐-动手学深度学习第二版
  10. 2.1 Apache Hadoop、HDFS - Apache Hadoop概述
  11. 在VS Code中使用Clang-Format
  12. FutureTask.get(timeOut)执行原理浅析
  13. c语言中缺少函数标题,error C2332: “struct”: 缺少标记名
  14. win10分屏快捷键无法使用_Win10分屏操作,再也不用来回切换视图了!
  15. Docker容器数据卷
  16. thinkpad 开机按f12
  17. 【Unity3DRPG入门学习笔记第六卷】SetCursor 设置鼠标指针
  18. SQL Server 2000服务无法启动,提示“系统找不到指定的文件”解决方法及sp4安装不上...
  19. 推荐几个pdf转txt免费软件,轻松让你做到pdf转txt
  20. 《大数据导论》之数据生命周期和数据使用

热门文章

  1. Vue的基本使用步骤
  2. iOS开发之iAd苹果广告
  3. access百度翻译 get_php百度翻译类
  4. python 乡镇轮廓 高德_百度高德地图小区景点边界轮廓实现
  5. Matlab绘制误差棒图----errorbar函数的使用
  6. 如何用一个鼠标控制多台电脑?
  7. 关于代码布局(Coding Layout)
  8. 学术-物理-维空间:五维空间
  9. Web项目 - 登录注册业务逻辑
  10. VQA相关概念简单整理