贪心算法解析

来源:互联网 发布:福岛核电站事故 知乎 编辑:程序博客网 时间:2024/06/05 08:55

贪心算法

一、基本概念

所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择也就是说,不从整体最优上加以考虑,
他所做出的仅是在某种意义上的局部最优解贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。
必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,
即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
    所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。

二、基本思路

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

三、适用情况

贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,
就可做出判断。
因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,
找到的解是否一定是问题的最优解。

四、实现框架

从问题的某一初始解出发;
    while (能朝给定总目标前进一步)
    { 
          利用可行的决策,求出可行解的一个解元素;
    }
    由所有解元素组合成问题的一个可行解;

五、实例分析

1.Jump Game

题目:Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.

分析:由于每层最多可跳A[i]步,也可以跳0步或1步,因此如果能到达最高层,则说明每一层都可以到达,
有了这个条件,说明可以用贪心算法
思路1:正向,从0出发,一层一层往上跳,看最后能不能超过最高层,能超过,说明能到达,否则不能到达
思路2:反向,从最高层往回走,一层一层往下跳,看最后能不能下降到第0层
思路3:可以用动规,设状态为分f[i],表示从第0层出发,走到A[i]时剩余的最大步数,则状态转移方程为:
f[i] =max(f[i-1]; A[i-1])-1; i >0

2.最小生成树

我们把构造连通网的最小代价生成树称为最小生成树(Minimum CostSpanning Tree),即遍历图中所有点经过的权值最小
普里姆(prim)算法
以某个顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树
void MiniSpanTree_Prim(MGraph G){int min,i,j,k;int adjvex[MAXVEX];int lowcost[MAXVEX];//保存相关顶点间边的权值lowcost[0]=0;  //lowcsot为0,表示顶点加入生成树adjvex[0]=0;for(i=1;i<G.numVertexes;i++){lowcost[i]=G.arc[0][i];adjvex[i]=0;}for(i=1;i<G.numVertexes;i++){min=INFINITY;j=1;k=0;while (j<G.numVertexes){if(lowcost[j]!=0 && lowcost[j]<min){min=lowcost[j];k=j;}j++;}printf("(%d,%d)",adjvex[k],k);lowcost[k]=0;for(j=1;j<G.numVertexes;j++){if(lowcost[j]!=0 && G.arc[k][j]<lowcost[j]){lowcost[j]=G.arc[k][j];adjvex[j]=k;}}}}
克鲁是卡尔(Kruskal)算法
typedef struct  {int begin;int end;int weight;}Edge; //边集数组元素void MiniSpanTree_Kruskal(MGraph G){int i,n,m;Edge edges[MAXEDGE];int parent[MAXVEX]; //定义一数组来判断边与边是否形成环路//将邻接矩阵G转化为边集数组edges并按权值由小到大排列for(i=0;i<G.numEdges;++i){n=Find(parent,edges[i].begin);m=Find(parent,edges[i].end);if(n!=m){parent[n]=m;printf("(%d,%d) %d",edges[i].begin,edges[i].end,edges[i].weight);}}}int Find(int * parent,int f){while (parent[f]>0){f=parent[f];}return f;}
//在边集中选择代价最小的边,若该边依附的顶点落在图中不同的连接分量上,就加入该边,否则舍去此边选择下一条代价最小的边。

原创粉丝点击