定义
是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。
例子
TSP问题设计题
贪心算法简介
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
贪心算法应用于TSP问题
贪心算法是一种算法策略,或者说问题求解的策略。基本思想是“今朝有酒今朝醉”。即一定要做当前情况下的最好选择,否则将来可能后悔,故名“贪心”。
将贪心算法应用于TSP问题中的求解思想:从某一个城市开始,每次选择一个城市,知道所有城市都被走完。注:每次在选择下一个城市的时候,只考虑当前情况,保证迄今为止经过的路径的总距离最短。
/*
外层循环:从i=1开始循环,i小于n, 初始化最短距离为10000(取一个大值,使其至少大于城市距离矩阵中的最大值)。即首先求出第1次将要访问的城市代号(利用中层循环及内层循环求解),然后将求出的第1次将要访问的城市代号j赋值给City[1],并将当前城市(代号0)至代号为j的城市的距离Dtmp累加至Sum。直至求出第n-1次要访问的城市代号。
中层循环:从k=1开始循环,k小于n,初始化Found的值为0。即先假设第i次要访问的城市代号为1,并判断代号为1的城市有没有出现在前几次访问过的城市中(利用内层循环判断),如果代号为1的城市没有出现在已经访问过的城市中并且当前城市(代号i-1)至代号为1的城市的距离小于Dtmp,那就把k=1的值赋值给j,再把当前城市(代号i-1)至代号为1的城市的距离赋值给Dtmp。直至循环到代号为n-1的城市,这样就能根据局部最短距离求出下一个城市的代号i与距离Dtmp。
内层循环:从l=0开始循环,l小于i,判断第l次访问过的城市代号是否与k的值相等,如果相等,代表第l次已经访问过代号为k的城市了,那么就将Found值置1,跳出循环。直至判断完第i-1次访问过的城市。
*/
#include <stdio.h>
#define n 4
int main(void) {
int Dis[n][n], City[n], Sum, i, j, k, l, Dtmp, Found;
City[0] = 0;
Sum = 0;
Dis[0][1] = 2; Dis[0][2] = 1; Dis[0][3] = 5; Dis[1][0] = 2; Dis[1][2] = 4;
Dis[1][3] = 4; Dis[2][0] = 1; Dis[2][1] = 4; Dis[2][3] = 6; Dis[3][0] = 5;
Dis[3][1] = 4; Dis[3][2] = 6;
for (i = 1; i < n; i++) {
Dtmp = 10000;
for (k = 1; k < n; k++) {
Found = 0;
for (l = 0; l < i; l++) {
if (City[l] == k) {
Found = 1;
break;
}
}
if (Found == 0 && Dis[City[i - 1]][k] < Dtmp) {
j = k;
Dtmp = Dis[City[i - 1]][k];
}
}
City[i] = j;
Sum = Sum + Dtmp;
}
Sum = Sum + Dis[j][0];
for (i = 0; i < n; i++) {
printf("%d\t", City[i]);
}
printf("\n");
printf("Sum = %d", Sum);
getchar();
}
一般背包问题
带期限的作业排序问题
定理5.2证明
定理5.3的证明
#include <iostream>
using namespace std;
/*D(1),…,D(n)是期限值。n≥1。作业已按p1≥p2≥…≥pn的顺序排序。
J(i)是最优解中的第i个作业,1≤i≤k。
终止时, D(J(i))≤D(J(i+1)), 1≤i<k
*/
void JS(int d[], int J[], int n, int &k)
{
int i, j, r;
d[0] = J[0] = 0;
k = 1;
J[1] = 1;
for (i = 2; i <= n; i++)
{
r = k;
while (d[J[r]] > d[i] && d[J[r]] != r)
r--;
if (d[J[r]] <= d[i] && d[i] > r)
{
for (j = k; j > r; j--)
J[j + 1] = J[j];
J[r + 1] = i;
k++;
}
}
}
int main()
{
int d[5] = { 0,2,1,2,1 };
int p[5] = { 0,100,20,15,10 };//已经按p值降序排才行哦!!!快排整一个
int J[5] = { 0 };
int k;
JS(d, J, 4, k);
for (int i = 1; i <= k; i++)
printf("%d-%d-%d ", p[J[i]], d[J[i]], J[i]);
return 0;
}
利用并查集实现的作业排序
贪心的特点
贪心的核心
定理5.1证明