您好,欢迎来到保捱科技网。
搜索
您的当前位置:首页实验二 贪心算法

实验二 贪心算法

来源:保捱科技网
实验二 贪心法(4学时)

上机实验一般应包括以下几个步骤:

(1)、准备好上机所需的程序。手编程序应书写整齐,并经人工检查无误后才能上机。 (2)、上机输入和调试自己所编的程序。一人一组,上机调试,上机时出现的问题,最好解决。 (3)、上机结束后,整理出实验报告。实验报告应包括:题目、程序清单、运行结果、对运行情况所作的分析。 一、实验目的与要求

1. 掌握贪心法的基本思想方法;

2. 了解适用于用贪心法求解的问题类型,并能设计相应贪心法算法; 3. 掌握贪心算法复杂性分析方法分析问题复杂性。 二、实验内容:

1、哈夫曼编码

设需要编码的字符集为{d1, d2, …, dn},它们出现的频率为{w1, w2, …, wn},应用哈夫曼树构造最短的不等长编码方案。设计贪心算法求解此哈夫曼编码方案;

2、删数问题

键盘输入一个高精度的正整数n(n<10位)去掉任意s个数字后剩下的数字按原左右次序组成一个新的正整数。编程对给定的n和s,寻找一种方案,使得剩下的数最小。 3、贪心背包问题

已知一个容量为M的包和n件物品, 每件物品的重量为wi, 效益值为pi. 若将物品i的一部分0≤xi≤1装入包中, 背包可得到pixi的效益值增量. 要求找到一种装入物品的方案, 在不超过包的总容量前提下, 使包获得最大效益值。

三、实验步骤

1. 理解算法思想和问题要求; 2. 编程实现题目要求;

3. 上机输入和调试自己所编的程序; 4. 验证分析实验结果; 5. 整理出实验报告。 四、实验要求

1)上述题目任选两道做。 2)完成程序代码的编写 3)完成实验及实验报告

附:实验报告的主要内容 一.实验目的

二.问题描述 三.解题思路 四.算法设计

包含:数据结构与核心算法的设计描述、函数调用及主函数设计、主要算法流程图等 五.程序调试及运行结果分析 六.实验总结

附录:程序清单 (程序过长,只附主要部分)

五、实验原理

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。 A、贪心算法的基本思路

1.建立数学模型来描述问题。

2.把求解的问题分成若干个子问题。

3.对每一子问题求解,得到子问题的局部最优解。 4.把子问题的解局部最优解合成原来解问题的一个解。 B、实现该算法的过程:

从问题的某一初始解出发;

while 能朝给定总目标前进一步 do 求出可行解的一个解元素;

由所有解元素组合成问题的一个可行解。 C、贪心算法的适用的问题:

贪心算法适用的问题必须满足两个属性: (1) 贪心性质:整体的最优解可通过一系列局部最优解达到,并且每次的选择可以依赖以前做出的选择,但不能依赖于以后的选择。

(2) 最优子结构:问题的整体最优解包含着它的子问题的最优解。 D、贪心算法的基本步骤

(1) 分解:将原问题分解为若干相互的阶段。 (2) 解决:对于每一个阶段求局部的最优解。 (3) 合并:将各个阶段的解合并为原问题的解。

附注:部分实验代码

1、哈夫曼编码 数据结构与算法

typedef char *HuffmanCode; //动态分配数组,存储哈夫曼编码 typedef struct {

unsigned int weight; //用来存放各个结点的权值

unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针 } HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树

核心源代码

#include #include #include

typedef struct {

unsigned int weight; //用来存放各个结点的权值

unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针 } HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树

typedef char *HuffmanCode; //动态分配数组,存储哈夫曼编码

//选择两个parent为0,且weight最小的结点s1和s2 void Select(HuffmanTree *ht,int n,int *s1,int *s2) {

int i,min;

for(i=1; i<=n; i++) {

if((*ht)[i].parent==0) {

min=i; break; } }

for(i=1; i<=n; i++) {

if((*ht)[i].parent==0) {

if((*ht)[i].weight<(*ht)[min].weight) min=i; } }

*s1=min;

for(i=1; i<=n; i++) {

if((*ht)[i].parent==0 && i!=(*s1)) {

min=i; break; } }

for(i=1; i<=n; i++) {

if((*ht)[i].parent==0 && i!=(*s1)) {

if((*ht)[i].weight<(*ht)[min].weight) min=i; } }

*s2=min; }

//构造哈夫曼树ht,w存放已知的n个权值

void CrtHuffmanTree(HuffmanTree *ht,int *w,int n) {

int m,i,s1,s2;

m=2*n-1; //总共的结点数

*ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); for(i=1; i<=n; i++) //1--n号存放叶子结点,初始化 {

(*ht)[i].weight=w[i]; (*ht)[i].LChild=0; (*ht)[i].parent=0; (*ht)[i].RChild=0; }

for(i=n+1; i<=m; i++) //非叶子结点的初始化 {

(*ht)[i].weight=0; (*ht)[i].LChild=0; (*ht)[i].parent=0; (*ht)[i].RChild=0; }

printf(\"\\n哈夫曼树为: \\n\");

for(i=n+1; i<=m; i++) //创建非叶子结点,建哈夫曼树

{ //在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2

Select(ht,i-1,&s1,&s2);

(*ht)[s1].parent=i; (*ht)[s2].parent=i; (*ht)[i].LChild=s1; (*ht)[i].RChild=s2;

(*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;

printf(\"%d (%d, %d)\\n\ }

printf(\"\\n\"); }

//从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码 void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n) {

char *cd; //定义的存放编码的空间 int a[100];

int i,start,p,w=0; unsigned int c;

hc=(HuffmanCode *)malloc((n+1)*sizeof(char *)); //分配n个编码的头指针 cd=(char *)malloc(n*sizeof(char)); //分配求当前编码的工作空间 cd[n-1]='\\0'; //从右向左逐位存放编码,首先存放编码结束符

for(i=1; i<=n; i++) //求n个叶子结点对应的哈夫曼编码 {

a[i]=0;

start=n-1; //起始指针位置在最右边

for(c=i,p=(*ht)[i].parent; p!=0; c=p,p=(*ht)[p].parent) //从叶子到根结点求编码 {

if( (*ht)[p].LChild==c) { cd[--start]='1'; //左分支标1 a[i]++; } else { cd[--start]='0'; //右分支标0 a[i]++; } }

hc[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间 strcpy(hc[i],&cd[start]); //将cd复制编码到hc }

free(cd);

for(i=1; i<=n; i++)

printf(\" 权值为%d的哈夫曼编码为:%s\\n\ for(i=1; i<=n; i++)

w+=(*ht)[i].weight*a[i];

printf(\" 带权路径为:%d\\n\ }

void main() {

HuffmanTree HT; HuffmanCode HC; int *w,i,n,wei;

printf(\"**哈夫曼编码**\\n\" ); printf(\"请输入结点个数:\" ); scanf(\"%d\

w=(int *)malloc((n+1)*sizeof(int));

printf(\"\\n输入这%d个元素的权值:\\n\

for(i=1; i<=n; i++) {

printf(\"%d: \ fflush(stdin);

scanf(\"%d\ w[i]=wei; }

CrtHuffmanTree(&HT,w,n); CrtHuffmanCode(&HT,&HC,n); }

2、删数问题

#include

int Del(int D,int a[10],int n)//D 删除几位 a 数组 n 当前数组位数 { int res,max,i,j,x[10]; for(i=0;i{

max=0; j=0; for(i=0;ires=0;

for(i=0;iint Res,D,z,n,m,i,a[10]; //m=43252556; i=0; n=0;

printf(\"<------------------删数问题---------------------->\\n\"); printf(\"请输入一个高精度的正整数N(N<=10位):\"); scanf(\"%d\

printf(\"请输入要去掉数字的位数S(S<=N):\"); scanf(\"%d\while(1) { z=m/10; a[i]=m-z*10; m=z; i++; n++; if(m==0) break; }

Res=Del(D,a,n);

printf(\"删除后的结果为:\"); printf(\"%d\\n\

3贪心背包问题

#include #include #include int min(int w,int c) {int temp;

if (wint max(int w,int c) {

int temp;

if (w>c) temp=w; else temp=c; return temp; }

void knapsack(int v[],int w[],int c,int n,int**m) //求最优值 {

int jmax=min(w[n]-1,c); for(int j=0;j<=jmax;j++) m[n][j]=0;

for(int jj=w[n];jj<=c;jj++) m[n][jj]=v[n];

for(int i=n-1;i>1;i--){ //递归部分 jmax=min(w[i]-1,c); for(int j=0;j<=jmax;j++) m[i][j]=m[i+1][j]; for(int jj=w[i];jj<=c;jj++)

m[i][jj]=max(m[i+1][jj],m[i+1][jj-w[i]]+v[i]); }

m[1][c]=m[2][c]; if(c>=w[1])

m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]); cout<<\"最优值:\"<int traceback(int **m,int w[],int c,int n,int x[]) //回代,求最优解 {

cout<<\"得到的一组最优解如下:\"<if(m[i][c]==m[i+1][c]) x[i]=0;

else {x[i]=1; c-=w[i];}

x[n]=(m[n][c])?1:0; for(int y=1;y<=n;y++)

cout<void main() {

int n,c; int **m;

cout<<\"请输入物品个数和重量上限:\"; cin>>n>>c;

int *v=new int[n+1];

cout<<\"请输入价值 (v[i]):\"<>v[i];

int *w=new int[n+1];

cout<<\"请输入重量 (w[i]):\"<>w[j];

int *x=new int[n+1];

m=new int*[n+1]; //动态的分配二维数组 for(int p=0;p

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- baoaiwan.cn 版权所有 赣ICP备2024042794号-3

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务