c语言程序设计——贪心算法

合集下载

贪心算法程序设计

贪心算法程序设计

贪心算法程序设计贪心算法程序设计1. 什么是贪心算法贪心算法(Greedy Algorithm)是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。

贪心算法的核心思想是局部最优解能导致全局最优解。

2. 贪心算法的基本步骤贪心算法的基本步骤如下:1. 定义问题的优化目标。

2. 将问题分解成子问题。

3. 选择当前最优的子问题解,将子问题的解合并成原问题的解。

4. 检查是否达到了问题的优化目标,如果没有达到,则回到第二步,继续寻找下一个最优子问题解。

5. 在所有子问题解合并成原问题解后,得到问题的最优解。

3. 贪心算法的应用场景贪心算法的应用非常广泛,几乎可以用于解决各种优化问题。

以下几个常见的应用场景:1. 零钱找零问题:给定一定面额的纸币和硬币,如何找零使得所需纸币和硬币的数量最小?2. 区间调度问题:给定一些活动的开始时间和结束时间,如何安排活动使得可以办理的活动数量最大?3. 背包问题:给定一些具有重量和价值的物品,如何选择物品使得背包的总价值最大?4. 最小树问题:给定一个带权无向图,如何找到一棵树,使得它的边权之和最小?5. 哈夫曼编码问题:给定一组字符和相应的频率,如何构造一个满足最低编码长度限制的二进制编码?4. 贪心算法的优缺点贪心算法的优点是简单、高效,可以快速得到一个近似最优解。

而且对于一些问题,贪心算法能够得到全局最优解。

贪心算法的缺点在于它不一定能够得到全局最优解,因为在每一步只考虑局部最优解,无法回溯到之前的选择。

5. 贪心算法的程序设计在使用贪心算法进行程序设计时,通常需要以下几个步骤:1. 定义问题的优化目标。

2. 将问题分解成子问题,并设计子问题的解决方案。

3. 设计贪心选择策略,选择局部最优解。

4. 设计贪心算法的递推或迭代公式。

5. 判断贪心算法是否能够得到全局最优解。

6. 编写程序实现贪心算法。

6.贪心算法是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。

贪心算法几个经典例子c语言

贪心算法几个经典例子c语言

贪心算法几个经典例子c语言1. 零钱兑换问题题目描述:给定一些面额不同的硬币和一个总金额,编写一个函数来计算可以凑成总金额所需的最少的硬币个数。

如果没有任何一种硬币组合能够凑出总金额,返回 -1。

贪心策略:每次选择面额最大的硬币,直到凑出总金额或者无法再选择硬币为止。

C语言代码:int coinChange(int* coins, int coinsSize, int amount){int count = 0;for(int i = coinsSize - 1; i >= 0; i--){while(amount >= coins[i]){amount -= coins[i];count++;}}return amount == 0 ? count : -1;}2. 活动选择问题题目描述:有 n 个活动,每个活动都有一个开始时间和结束时间,选择一些活动使得它们不冲突,且能够参加的活动数最多。

贪心策略:每次选择结束时间最早的活动,直到所有活动都被选择或者无法再选择为止。

C语言代码:typedef struct{int start;int end;}Activity;int cmp(const void* a, const void* b){return ((Activity*)a)->end - ((Activity*)b)->end;}int maxActivities(Activity* activities, int n){qsort(activities, n, sizeof(Activity), cmp);int count = 1;int end = activities[0].end;for(int i = 1; i < n; i++){if(activities[i].start >= end){count++;end = activities[i].end;}}return count;}3. 跳跃游戏题目描述:给定一个非负整数数组,你最初位于数组的第一个位置。

c语言贪心算法

c语言贪心算法

c语言贪心算法一、引言贪心算法是一种在每一步选择中都采取当前情况下的最佳(或最优)选择的算法,它希望通过做出局部最优选择来获得全局最优解。

在C语言中,贪心算法是一种常用的优化方法,可以应用于各种问题领域,如资源分配、背包问题、图着色等。

二、基本概念贪心算法的基本思想是,在每一步选择中,总是做出在当前看来最好的选择,期望最终能得到最优解。

贪心算法并不保证得到最优解,但在很多情况下能得到满意的结果。

在C语言中,可以使用结构体、数组等数据结构来实现贪心算法。

三、应用示例以下是一个简单的贪心算法示例,用于解决公交线路规划问题。

假设有n个公交站点,我们希望通过贪心算法来规划一条公交线路,使得线路长度最短。

```c#include<stdio.h>#include<stdlib.h>typedefstruct{intstart;//起点站编号intend;//终点站编号intdistance;//站点之间的距离}Station;//贪心算法选择站点intgreedy_route(Station*stations,intn){inti,j;intbest_distance=stations[0].distance;//初始化起点站到终点的距离为最小距离intbest_route=stations[0].start;//初始化最佳路线为起点站for(i=1;i<n;i++){//考虑所有可能的路线组合,找出当前距离最短的路线和最近的站点作为下一个站点for(j=0;j<i;j++){if(stations[j].distance+stations[i].distance<best_distance){best_distance=stations[j].distance+stations[i].distance;best_route=stations[i].end;//更新最佳路线为最近的站点}}//将当前站点加入路线中stations[i].start=best_route;//将终点站编号赋值给当前站点起始站编号}returnbest_route;//返回最终的公交线路编号}```四、总结通过以上示例,我们可以看到贪心算法在公交线路规划问题中的应用。

贪心算法模板

贪心算法模板

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。

贪心算法并不总是得到问题的最优解,但对许多问题它能产生整体最优解或整体最优解的近似解。

下面是一个简单的贪心算法模板,用于解决一些优化问题:pythondef greedy_algorithm(input_data):# 初始化结果变量result = []# 根据输入数据的特性进行排序或预处理sorted_data = sort_or_preprocess(input_data)# 遍历排序后的数据for item in sorted_data:# 检查是否满足某个条件,例如是否可以选择该元素if can_choose(item, result):# 如果满足条件,则选择该元素并更新结果result.append(item)# 可能还需要执行一些额外的操作,例如更新状态或计数器update_state(result, item)return result# 根据具体问题的需要,实现排序或预处理函数def sort_or_preprocess(input_data):# 对输入数据进行排序或预处理pass# 根据具体问题的需要,实现选择条件函数def can_choose(item, result):# 检查是否可以选择该元素pass# 根据具体问题的需要,实现状态更新函数def update_state(result, item):# 更新状态或计数器pass请注意,这只是一个通用的贪心算法模板,具体实现会根据问题的不同而有所变化。

在实际应用中,你需要根据问题的特点来设计合适的排序、选择和状态更新策略。

同时,也需要验证贪心策略是否能够得到全局最优解,或者是否能够得到满意的近似解。

1。

贪心算法最短路径问题c语言代码

贪心算法最短路径问题c语言代码

贪心算法最短路径问题c语言代码贪心算法最短路径问题C语言代码在计算机算法的领域中,贪心算法是一种常见的解决问题的方法。

贪心算法是一种寻找最优解的方法,就是在每个步骤中都采取最优的选择,这样每一步的最优解最终就可以得到整体的最优解。

在实际应用中,贪心算法通常被用于NP问题的解决,例如最短路径问题。

本文将介绍如何用C语言实现贪心算法解决最短路径问题。

1. 最短路径问题概述最短路径问题是一种图论问题,是指在一个有权重的有向图或无向图中,从一个指定的起点节点到达一个指定终点节点的最短路径问题。

在实际应用中,最短路径问题的应用非常广泛,例如地图导航、网络寻路、信息传递等等。

2. 贪心算法的原理贪心算法是一种自顶向下的设计方法,它主要依赖与一种贪心的选择方法。

在每个步骤中,都会选择能够最优化当前直接的步骤的答案。

因此,当遇到问题难以确定最优解时,可以使用贪心算法。

一般来说,贪心算法的优点是简单易懂,并且在特定情况下能够得到准确的答案。

3. C语言代码实现快速查找从起点到所有节点的距离是这个问题的关键,可以使用某种最短路算法,例如Dijkstra算法或贪心算法。

在这里,我们使用贪心算法解决最短路径问题。

以下是C语言代码示例:#include <stdio.h> #include <stdlib.h> #include <string.h>#define V 6int min_distance(int distance[], int visited[]) { int min_index, min_distance = INT_MAX;for (int i = 0; i < V; i++) { if (visited[i] == 0 && distance[i] <= min_distance){ min_distance = distance[i]; min_index = i; } }return min_index; }int dijkstra(int graph[V][V], int source, int destination) { int distance[V], visited[V], count; memset(distance, 0, sizeof(distance)); memset(visited, 0, sizeof(visited));for (int i = 0; i < V; i++){ distance[i] = INT_MAX; }distance[source] = 0;for (count = 0; count < V - 1; count++){ int u = min_distance(distance, visited);visited[u] = 1;for (int v = 0; v < V; v++){ if (!visited[v] && graph[u][v] &&distance[u] != INT_MAX && distance[u] + graph[u][v]< distance[v]) { distance[v] =distance[u] +graph[u][v]; } } }return distance[destination]; }int main() { int graph[V][V] = { { 0, 1, 0,0, 0, 0 }, { 0, 0, 9, 0, 0,0 }, { 2, 0, 0, 3, 0, 1 }, { 0, 0, 0, 0, 2, 0 }, { 4,6, 0, 2, 0, 0 }, { 0, 0, 0,0, 1, 0 } };int source = 0, destination = 5;int distance = dijkstra(graph, source,destination);printf("The shortest distance from node %dto %d is: %d\n", source, destination, distance);return 0; }4. 结尾在本文中,我们介绍了贪心算法解决最短路径问题的原理和C语言代码实现。

C语言版贪心算法背包问题

C语言版贪心算法背包问题

C语言版贪心算法背包问题#include#define N 100typedef struct bao{int num;float w;float v;};typedef struct avg{int num;float val;float w;float v;};struct bao b[N];struct avg d[N];int n;float c;void Sort(){int i,j,k;struct avg temp[N];for(i=0;i<n-1;i++)< p="">{k = i;for(j=i+1;j<n;j++)< p="">if(d[k].valif(k != i){temp[i]=d[i];d[i]=d[k];d[k]=temp[i];}}}float knapsack(){int i;float x[N],sum = 0;for(i=0;ifor(i=0;i<n;i++){< p="">if(d[i].w>c) break;x[d[i].num] = 1;sum += d[i].v;c -= d[i].w;}if(i<n){< p="">x[d[i].num] = c/d[i].w;sum += x[d[i].num] * d[i].v;}return sum;}int main(){int i,j,k;float sum;printf("请输入物品总数:");scanf("%d",&n);printf("\n请输入背包容量:");scanf("%f",&c);printf("\n请输入各物品重量及价值(格式:xx,xx):");for(i=0;i<n;i++){< p=""> scanf("%f,%f",&b[i].w,&b[i].v); }for(i=0;i<="" p="">for(i=0;i<n;i++){< p="">d[i].val = b[i].v/b[i].w;d[i].v = b[i].v;d[i].w = b[i].w;}Sort();sum = knapsack();printf("%.2f\n",sum);}</n;i++){<></n;i++){<></n){<></n;i++){<></n;j++)<></n-1;i++)<>。

prim算法c语言

prim算法c语言什么是Prim算法?Prim算法,也叫普里姆算法,是一种用于求解最小生成树的贪心算法。

最小生成树是指在一个无向连通图中,连接所有节点且边权值之和最小的树。

Prim算法的基本思想是从一个起始节点开始,每次选择与当前已经构建好的部分形成的子图相连的、权值最小的边所连接的节点,并将该节点加入到已经构建好的部分中。

直到所有节点都被加入到已经构建好的部分中,此时得到了一棵最小生成树。

Prim算法步骤1. 选定一个起点作为已经构建好的部分。

2. 将与该起点相连且未被访问过的边加入到候选集合中。

3. 从候选集合中选择一条权值最小的边连接到未被访问过的节点,并将该节点加入到已经构建好的部分中。

4. 将新加入节点所连接且未被访问过的边加入到候选集合中。

5. 重复步骤3和步骤4,直至所有节点都被加入到已经构建好的部分中。

Prim算法C语言实现下面给出Prim算法C语言实现代码:```#include <stdio.h>#include <stdlib.h>#include <limits.h>#define MAX_VERTICES 100#define INF INT_MAXtypedef struct {int weight;int visited;} Vertex;typedef struct {int vertices[MAX_VERTICES][MAX_VERTICES]; int num_vertices;} Graph;void init_graph(Graph *graph, int num_vertices) {graph->num_vertices = num_vertices;for (int i = 0; i < num_vertices; i++) {for (int j = 0; j < num_vertices; j++) {graph->vertices[i][j] = INF;}}}void add_edge(Graph *graph, int u, int v, int weight) { graph->vertices[u][v] = weight;graph->vertices[v][u] = weight;}void prim(Graph *graph) {Vertex vertices[MAX_VERTICES];for (int i = 0; i < graph->num_vertices; i++) {vertices[i].weight = INF;vertices[i].visited = 0;}vertices[0].weight = 0;for (int i = 0; i < graph->num_vertices - 1; i++) {// 找到未访问过的权值最小的节点int min_vertex_index = -1;for (int j = 0; j < graph->num_vertices; j++) {if (!vertices[j].visited && (min_vertex_index == -1 || vertices[j].weight < vertices[min_vertex_index].weight)) { min_vertex_index = j;}}// 将该节点标记为已访问vertices[min_vertex_index].visited = 1;// 更新与该节点相连的未访问过的节点的权值for (int j = 0; j < graph->num_vertices; j++) {if (!vertices[j].visited && graph->vertices[min_vertex_index][j] < vertices[j].weight) {vertices[j].weight = graph->vertices[min_vertex_index][j];}}}// 输出最小生成树printf("Minimum Spanning Tree:\n");for (int i = 1; i < graph->num_vertices; i++) {printf("%d - %d (%d)\n", i, (i - 1), vertices[i].weight); }}int main() {Graph graph;init_graph(&graph, 6);add_edge(&graph, 0, 1, 6);add_edge(&graph, 0, 2, 1);add_edge(&graph, 0, 3, 5);add_edge(&graph, 1, 4, 3);add_edge(&graph, 2, 4, 5);add_edge(&graph, 2, 3, 5);add_edge(&graph, 2, 5, 4);add_edge(&graph, 3 ,5 ,2);prim(&graph);return EXIT_SUCCESS;}```代码解释- 定义了Vertex结构体,用于存储节点的权值和访问状态。

数据结构 dijkstra算法 c语言

数据结构 dijkstra算法 c语言Dijkstra 算法是一种用于找到图中从一个顶点到其他顶点的最短路径的贪心算法。

以下是一个使用 C 语言实现 Dijkstra 算法的示例代码:```c#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#define MAX顶点数 100// 图的邻接表表示typedef struct {int顶点;struct Edge* edges;} Vertex;// 边的结构typedef struct Edge {int weight;Vertex* destination;struct Edge* next;} Edge;// 初始化图void initGraph(Vertex* graph, int vertices) {for (int i = 0; i < vertices; i++) {graph[i].edges = NULL;}}// 在图中添加边void addEdge(Vertex* graph, int source, int destination, int weight) {Edge* edge = (Edge*)malloc(sizeof(Edge));edge->weight = weight;edge->destination = &graph[destination];edge->next = graph[source].edges;graph[source].edges = edge;}// Dijkstra 算法找到从源顶点到其他顶点的最短路径void dijkstra(Vertex* graph, int source) {int vertices = MAX顶点数;int distance[vertices];bool visited[vertices];// 初始化距离和访问状态for (int i = 0; i < vertices; i++) {distance[i] = INT_MAX;visited[i] = false;}// 源顶点的距离为 0distance[source] = 0;// 循环找到最短路径while (1) {int minVertex = -1;for (int i = 0; i < vertices; i++) {if (!visited[i] && distance[i] < distance[minVertex]) {minVertex = i;}}if (minVertex == -1) {break;}visited[minVertex] = true;for (Edge* edge = graph[minVertex].edges; edge != NULL; edge =edge->next) {int destination = edge->destination->顶点;if (!visited[destination] && distance[minVertex] != INT_MAX && distance[minVertex] + edge->weight < distance[destination]) {distance[destination] = distance[minVertex] + edge->weight;}}}// 打印最短距离for (int i = 0; i < vertices; i++) {if (i == source) {continue;}printf("从顶点%d 到顶点%d 的最短距离为: %d\n", source, i, distance[i]);}}int main() {// 图的顶点数和边数int vertices = 9, edges = 14;// 创建图的邻接表Vertex graph[vertices];initGraph(graph, vertices);// 添加边addEdge(graph, 0, 1, 4);addEdge(graph, 0, 7, 8);addEdge(graph, 1, 2, 8);addEdge(graph, 1, 7, 11);addEdge(graph, 2, 3, 7);addEdge(graph, 2, 8, 2);addEdge(graph, 3, 4, 9);addEdge(graph, 3, 5, 14);addEdge(graph, 4, 5, 10);addEdge(graph, 5, 6, 2);addEdge(graph, 5, 8, 6);addEdge(graph, 6, 7, 1);addEdge(graph, 6, 8, 7);// 执行 Dijkstra 算法dijkstra(graph, 0);return 0;}```上述代码实现了一个使用 Dijkstra 算法的示例程序。

贪心算法_实验报告

贪心算法_实验报告一、设计分析●问题描述:键盘输入一个高精度的正整数N(N不超过240位),去掉其中任意S个数字后剩下的数字按原左右次序将组成一个新的正整数。

编程对给定的N和S,寻找一种方案使得剩下的数字组成的新数最小。

●设计思路:在位数固定的前提下,让高位的数字尽量小其值就较小,依据此贪心策略解决此问题。

删除高位较大的数字。

具体:相邻两位比较若高位比低位大则删除高位。

删除字符的方法:1)物理删除,用后面的字符覆盖已删除的字符。

有比较多字符移动操作,算法效率不高。

2)用数组记录字符的状态,“1”表示对应数字存在,“0”表示对应数字已删除。

3)利用数组,记录未删除字符的下标:n=“1 2 4 3 5 8 3 3”0 0 0 0 0 04比3大删除“1 2 3 5 8 3 3” 1 2 4 5 0 08比3大删除“1 2 3 5 3 3” 1 2 4 5 05比3大删除“1 2 3 3 3” 1 2 4 7 8二、程序代码c语言实现#include<stdio.h>#include<string.h>#define N 10000int main(void){char a[N];int i,j,k,n;printf("输入要处理的数据:\n");gets(a);printf("输入要删除的数字个数:\n");scanf("%d",&n);三、测试用例四、实验总结加深了对贪心算法的理解与运用。

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

这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。

动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。

c++贪心算法经典例题

c++贪心算法经典例题和详解贪心算法(Greedy Algorithm)是一种优化问题解决方法,其基本思想是每一步都选择当前状态下的最优解,以期望达到全局最优解。

贪心算法的特点是每一步都要做出一个局部最优的选择,而这些局部最优选择最终构成了全局最优解。

下面是一个经典的贪心算法例题以及详解:例题:活动选择问题(Activity Selection Problem)假设有一个需要在同一时段使用同一个资源的活动集合,每个活动都有一个开始时间和结束时间。

设计一个算法,使得能够安排最多数量的互不相交的活动。

# 输入:-活动的开始时间数组`start[]`。

-活动的结束时间数组`end[]`。

# 输出:-选择的互不相交的活动的最大数量。

# 算法详解:1. 首先,将活动按照结束时间从小到大排序。

2. 选择第一个活动,并将其加入最终选择的集合中。

3. 对于剩下的活动,选择下一个结束时间最早且与前一个活动不冲突的活动。

4. 重复步骤3,直到所有活动都被选择。

```cpp#include <iostream>#include <algorithm>#include <vector>using namespace std;// 定义活动结构体struct Activity {int start, end;};// 比较函数,用于排序bool compareActivities(Activity a, Activity b) {return a.end < b.end;}// 贪心算法解决活动选择问题void activitySelection(vector<Activity>& activities) {// 按照结束时间排序sort(activities.begin(), activities.end(), compareActivities);// 第一个活动总是被选中cout << "Selected activity: (" << activities[0].start << ", " << activities[0].end << ")" << endl;// 选择其余活动int lastSelected = 0;for (int i = 1; i < activities.size(); i++) {// 如果当前活动的开始时间大于等于上一个选择的活动的结束时间,则选择该活动if (activities[i].start >= activities[lastSelected].end) {cout << "Selected activity: (" << activities[i].start << ", " << activities[i].end << ")" << endl;lastSelected = i;}}}int main() {vector<Activity> activities = {{1, 2}, {3, 4}, {0, 6}, {5, 7}, {8, 9}, {5, 9}};cout << "Activities before sorting:" << endl;for (const Activity& activity : activities) {cout << "(" << activity.start << ", " << activity.end << ") ";}cout << endl;activitySelection(activities);return 0;}```在这个例子中,我们首先定义了一个活动的结构体`Activity`,然后编写了一个比较函数`compareActivities` 用于排序。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
i=1 n
达到最大,同时满足 Σ Wixi≦M
i=1
n
算法描述
例 给定n=3,M=40, (W1,W2,W3)= (28,15,24), (P1,P2,P3)=(35,25,24)。五个可能的解如下: (x1,x2,x3) Σ Wixi≦M ∑ Pixi 1 (1,4/5,0) 40 55 先装利润最大 2 (1/2,1,1/3) 37 50.5 3 (1/28,1,1) 40 50.25 先装重量最小 4 (5/7,1,5/24) 40 55 5 (25/28,1,0) 40 56.25 先装利润重量 比值最大

动态规划算法: 1.全局最优解中一定包含某个 局部最优解,但不一定包含前一个局部最优 解,因此需要记录之前的所有最优解 2.动态 规划的关键是状态转移方程,即如何由以求 出的局部最优解来推导全局最优解 3.边界条 件:即最简单的,可以直接得出的局部最优 解
贪心算法每一步都做目前最好的选择,不考虑下一步 的选择。 动态规划的子问题每一步求的最优解影响下一个问题 的最优解。 贪心算法是种策略,思想。。。 它并没有固定的模式 动态规划的思想是分治+解决冗余 把一个复杂的问题分解成一块一块的小问题 每一个小问题中得到最优解 再从这些最优解中获取更优的答案
将输入的时间按从小到大排序; 将排序后的时间按顺序依次放入每个水龙头的队 列中; 统计,输出答案。
【例6】设有n个正整数,将他们连接成一排, 组成一个最大的多位整数。例如:n=3时,3个整 数13,312,343,连成的最大整数为:34331213 又如:n=4时,4个整数7,13,4,246连接成的最大整 数为7424613 输入:N N个数 输出:连接成的多位数
问题描述 算法描述 算法证明 算法分析
问题描述
问题:给定n种不同物品和一个背包,背包容 量为M,物品i的重量是Wi,装物品i的利润是 Pi ,假定物品i的一部分xi(0≦ xi ≦1),放进 背包,得到利润Pi xi 问:应该如何装包,才能获得最大利润?
问题描述
给定M>0,Wi>0,Pi>0, 1≦ i ≦n,要求找一个n元 向量(x1,x2,…,xn), 0≦ xi ≦1, 1≦ i ≦n,使得 ∑ Pixi
算法证明
定理 如果P1/W1 ≧ P2/W2 ≧… ≧ Pn/Wn ,算 法 GREEDY_ KNAPSACK 产生背包问题的 一个最优解。 证明:设(x1,x2,…,xn)是算法产生的一个解,不 失一般性,设存在某个j,1≦j≦n, x1 = x2 = … = xj-1=1, 0≦ xj<1, xj+1 = xj+2 = … = xn =0。

贪心算法的基本要素
对于一个具体的问题,怎么知道是否可用 贪心算法解此问题,以及能否得到问题的最 优解呢?这个问题很难给予肯定的回答。 但是,从许多可以用贪心算法求解的问 题中看到这类问题一般具有2个重要的性质: 贪心选择性质和最优子结构性质。
1、贪心选择性质
所谓贪心选择性质是指所求问题的整体最 优解可以通过一系列局部最优的选择,即贪心 选择来达到。这是贪心算法可行的第一个基本 要素,也是贪心算法与动态规划算法的主要区 别。
3、贪心算法与动态规划算法的差异
贪心算法和动态规划算法都要求问题具 有最优子结构性质,这是2类算法的一个 共同点。但是,对于具有最优子结构的问 题应该选用贪心算法还是动态规划算法求 解?是否能用动态规划算法求解的问题也 能用贪心算法求解?
(例如“0-1背包问题”与“部分背包问题”)
0-1背包问题
Σ Wixi’= Σ Wixi’ +wkxk’
i=1 i=1
k
所以有:
Σ Wixi’> Σ Wixi =M
i=1 i=1
k
说明 (x1’, x2’,…,xn’)不是问题的解。矛盾。 综合1和2两种情形,算法产生一个最优解。
算法分析
时间复杂性 O(n) 空间复杂性 O(n)
贪心法的基本思想
一种多步决策方法 ◆每一步使目标函数值增加最快或最慢 ◆选择最优化量度是方法的关键
使用贪心算法的关键:
1. 该题是否适合于用贪心策略求解 2. 如何选择贪心标准,以得到问题的最优解
例5: 排队打水问题2
有N个人排队到R个水龙头去打水,他们装满水 桶的时间为T1,T2,…,Tn为整数且各不相 等,应如何安排他们的打水顺序才能使他们 总的花费的时间最少(包括等待时间)?
分析
由于排队时,越靠前面的计算的次数越多, 显然越小的排在越前面得出的结果越小 (可以用数学方法简单证明,这里就不再 赘述),所以这道题可以用贪心法解答, 基本步骤:
给定一个最大载重量为M的卡车和N种 动物。已知第i种动物的重量为Wi,其最大 价值为Vi,设定M,Wi,Vi均为整数,编程 确定一个装货方案,使得装入卡车中的所 有动物总价值最大。
算法?
按贪心法,有反例. 设N=3,卡车最大载重量是100,三种动物A、 B、C的重量分别是40,50,70,其对应的 总价值分别是90、100、150。
算法分析: 此题很容易想到使用贪心法,但如何贪?整数 按从大到小的顺序连接起来,样例符合。再 想想,我们还是可以找到反例:12,121 应 该组成12121而非12112。 是不是此题不能用贪心法呢? 正确的贪心标准是:先把整数化成字符串,然 后再比较a+b和b+a,如果a+b>b+a,就把a 排在b的前面,反之则把a排在b的后面。
对于一个具体问题,要确定它是否具有贪 心选择性质,必须证明每一步所作的贪心选择 最终导致问题的整体最优解。
17
2、最优子结构性质
当一个问题的最优解包含其子问题的 最优解时,称此问题具有最优子结构性质。 问题的最优子结构性质是该问题可用动态 规划算法或贪心算法求解的关键特征。
动态规划和贪心算法都是一种递推算法 均有局 部最优解来推导全局最优解 不同点: 贪心算 法: 1.贪心算法中,作出的每步贪心决策都 无法改变,因为贪心策略是由上一步的最优 解推导下一步的最优解,而上一部之前的最 优解则不作保留。 2.由(1)中的介绍,可 以知道贪心法正确的条件是:每一步的最优 解一定包含上一步的最优解。
于是可以通过增大xk’ 的取值,减小xk+1’, xk+2’,…, xn’的取值,构造优于(x1’, x2’,…,xn’)的解。矛盾。 2 xk< xk’ 。此种情况下必有xk< 1。
考虑到xi = xi ’(1≦i<k),有
Σ Wixi= Σ Wixi +wkxk
i=1 k i=1 k-1 k k-1
例2:如果硬币的币值改为1分,5分,1角1分三种, 现要找给顾客1角5分? 1个1角1分+4个1分??
贪心算法的定义
在求最优解问题的过程中,依据某种贪心 标准,从问题的初始状态出发,直接去求每一 步的最优解,通过若干次的贪心选择,最终得 出整个问题的最优解,这种求解方法就是贪心 算法。
部分背包问题
删数字问题
对给定的n位高精度正整数,去掉其中k(k<n)个数 字后,按原左右次序将组成一个新的正整数, (1)使得剩下的数字组成的新数最大。
(2)使得剩下的数字组成的新数最小?
算法描述
背包问题的贪心算法 输入:P(1:n),W(1:n),M,按P(i)/W(i) ≥P(i+1)/W(i+1)的顺序读入 输出:X(1:n)
Procedure GREEDY-KNAPSACK real:P(1:n) ,W(1:n),X(1:n),M,CU; Integer:i,n; begin 1.Read (P(1:n).W(1:n),M); //设按P(i)/W(i) ≥P(i+1)/W(i+1)的顺序读入// 2.for i=1 to n do 3. X(i)=0;//X(i)赋初值// 4.CU=M;//CU是背包问题的剩余容量// 5.I:=1; 6.while W[I] ≤CU do begin 7. X[I]:=1; 8. CU:=CU-W[I], 9. I:=I+1 end; 10.X[I]:=CU/W[I] end
贪心法的基本思想
例1:日常生活中经常会碰到找硬币的例子。现 有四种硬币,它们的面值分别是1元,5角, 1角和1分。现在要给顾客2元1角3分钱。如 何找使得所拿出的硬币个数最少?
贪心法
贪心法将一个最优决策过程变成多步决策过程, 并在每步总是做出当前看来是最好的选择。 贪心算法并不从全局最优上加以考虑,它所做的 选择只是在某种意义上的局部最优选择。
再设(x1’,x2’,…,xn’)是一个最优解,我们证 明(x1’,x2’,…,xn’)= (x1,x2,…,xn)。
若不然,必存在k,1≦k≦n, 1≦i<k,有xi = xi ’ ,xk≠ xk’。于是有两种情况: 1
k-1 i=1
xk> xk’ 。此种情况下可得到
k-1 i=1
Σ Wixi’+ Wkxk’ < Σ Wixi + Wkxk ≦M
相关文档
最新文档