完整版4+四+贪心算法+习题参考答案文档格式.docx

上传人:b****8 文档编号:22429003 上传时间:2023-02-04 格式:DOCX 页数:41 大小:117.56KB
下载 相关 举报
完整版4+四+贪心算法+习题参考答案文档格式.docx_第1页
第1页 / 共41页
完整版4+四+贪心算法+习题参考答案文档格式.docx_第2页
第2页 / 共41页
完整版4+四+贪心算法+习题参考答案文档格式.docx_第3页
第3页 / 共41页
完整版4+四+贪心算法+习题参考答案文档格式.docx_第4页
第4页 / 共41页
完整版4+四+贪心算法+习题参考答案文档格式.docx_第5页
第5页 / 共41页
点击查看更多>>
下载资源
资源描述

完整版4+四+贪心算法+习题参考答案文档格式.docx

《完整版4+四+贪心算法+习题参考答案文档格式.docx》由会员分享,可在线阅读,更多相关《完整版4+四+贪心算法+习题参考答案文档格式.docx(41页珍藏版)》请在冰豆网上搜索。

完整版4+四+贪心算法+习题参考答案文档格式.docx

10h的编码为:

推广到n个字符:

第1个字符:

n-1个1,

111

n1

第2个字符:

n-2个1,

1个0,

1110

n2

第3个字符:

n-3个1,

n3

第n-1个字符:

1个1,

10

第n个字符:

1个0

3.设p1,p2,,pn是准备存放到长为L的磁带上的n个程序,程序pi需要的n

带长为ai。

设aiL,要求选取一个能放在带上的程序的最大子集合(即其中

i1

含有最多个数的程序)Q。

构造Q的一种贪心策略是按ai的非降次序将程序计入集合。

集合。

1)证明这一策略总能找到最大子集Q,使得aiL。

piQ

2)设Q是使用上述贪心算法得到的子集合,磁带的利用率可以小到何种程度?

3)试说明1)中提到的设计策略不一定得到使a/L取最大值的子集合。

1)证明:

不妨设印a2...an,若该贪心策略构造的子集合Q为{印,玄2,,a$},

ss

则s满足aiL、asas1L。

i1i1

要证明能找到最大子集,只需说明s为可包含的最多程序段数即可。

即证不存在多于s个的程序集合Q{ail,ai2,,a}(ks),使得aL

piQ~

~k

反证法,假设存在多于s个的程序集Q{ai,ai2,,aik},(ks),满足a”L。

j1

因为a1

a2...an非降序排列,则a1a2

as

ak

ai1ai2

aikL。

因为k

s且为整数,则其前s+1项满足a1a2

as1

L。

s

这与贪心策略构造的子集和Q中s满足的as

as1L矛盾。

故假设不成立,

得证。

2)磁带的利用率为ai/L;

(甚至最小可为0,此时任意aiL或者aiL)piQpiQ

3)按照1)的策略可以使磁带上的程序数量最多,但程序的总长度不一定是最大的,假设{a1,a2,,ai}为Q的最大子集,但是若用ai1代替ai,仍满足

akaiiL,则佝耳,,a「,aii}为总长度更优子集。

k1

4.答案见后面所附程序。

5.已知n种货币56丄,Cn和有关兑换率的nn表R,其中R[i,j]是一个单位的

货币ci可以买到的货币cj的单位数。

1)试设计一个算法,用以确定是否存在一货币序列ci1,ci2,L,cik使得:

R[i1,i2]R[i2,i3]LR[ik,i1]1

2)设计一个算法打印出满足1)中条件的所有序列,并分析算法的计算时间。

解:

基本解题思想:

通过FLOYD算法求出最大环。

判断最大环的权值之积是否大于1,如果大于1说明可以实现套汇,如果不大于1说明不能实现套汇。

在求解最大环的同时记录下兑换过程中的步骤。

算法实现的数据结构:

intPath[MAX_VERTECX_NUM][MAX_VERTECX_NUM];

//用来记录套汇过程中要经过的路径floatvalue[MAX_VERTECX_NUM][MAX_VERTECX_NUM];

//用来记录经过讨回操作后得到的值//借助图来实现该算法

typedefstruct{

intvexs[MAX_VERTECX_NUM];

//顶点向量每种货币对应一个顶点

floatarc[MAX_VERTECX_NUM][MAX_VERTECX_NUM];

//邻接矩阵存放兑换率信息

intvexnum,arcnum;

//图中当前顶点数和弧数

}MGraph;

算法中的关键步骤:

for(k=1;

k<

=G->

vexnum;

k++)

{for(i=1;

i<

i++)

{for(j=1;

j<

j++)

{if(value[i][k]*value[k][j]>

value[i][j])//这里判断是否使兑换率增大,如果增大则记录下来{

value[i][j]=value[i][k]*value[k][j];

Path[i][j]=Path[k][j];

}

}在输出兑换序列时采用了递归算法:

这个算法逆序输出了兑换序列。

voidProcedure_print(inti,intj)

{if(Path[i][j]==i)

{

printf("

%d"

i);

return;

elseif(Path[i][j]==0)//输出结点i与结点j之间不存在通路printf("

NOpath"

);

else{printf("

%d"

Path[i][j]);

Procedure_print(i,Path[i][j]);

//{递归,货币I至J中间顶点}

此算法的时间复杂度是:

0("

3)

算法实现代码:

#include<

stdio.h>

#defineMAX_VERTECX_NUM20

#defineINT_MIN0

intn;

floatvalue[MAX_VERTECX_NUM][MAX_VERTECX_NUM];

typedefstruct{

//顶点向量可以存储每个顶点的信息

//邻接矩阵主要存放关于边的信息intvexnum,arcnum;

voidCreateDG(MGraph*G){

inti,j,k;

floatw;

scanf("

%d%d"

&

(G->

vexnum),&

arcnum));

printf("

G->

vexnum=%d,G->

arcnum=%d\n"

G->

vexnum,G->

arcnum);

for(i=1;

{G->

vexs[i]=i;

}for(i=1;

i++){

for(j=1;

arc[i][j]=INT_MIN;

arcnum;

scanf("

%d%d%f"

i,&

j,&

w);

arc[i][j]=w;

voidShortestPath_FLOYD(MGraph*G)

for(i=1;

if(i==j)value[i][j]=1;

else

value[i][j]=G->

arc[i][j];

if(G->

arc[i][j]>

INT_MIN)

Path[i][j]=i;

Path[i][j]=0;

if(value[i][k]*value[k][j]>

value[i][j])

voidProcedure_print(inti,intj)

if(Path[i][j]==i)

return;

elseif(Path[i][j]==0)//输出结点i与结点j之间不存在通路

intmain()

inti,j;

MGraphG;

freopen("

data.in"

"

r"

stdin);

data.out"

w"

stdout);

CreateDG(&

G);

ShortestPath_FLOYD(&

i=1;

if(value[i][i]>

1)

%f"

value[i][i]);

if(Path[i][i]!

=0)

%d%d"

i,i);

兑换顺序的逆序输出:

%d"

Procedure_print(i,i);

\n"

4.同学们的几种不同答案

构造哈夫曼树思想,将所有的节点放到一个队列中,用一个节点替换两个频率最低的节点,新节点的频率就是这两个节点的频率之和。

这样,新节点就是两个被替换节点的父节点了。

如此循环,直到队列中只剩一个节点(树根)。

答案1)

伪代码:

typedefstruct

unsignedintweight;

unsignedintparent,lchild,rchild;

}HTNode,*HuffmanTree;

typedefchar**HuffmanCode;

procHuffmanCoding(HuffmanTree&

HT,HuffmanCode&

HC,int*w,intn)ifn<

=1thenreturn

HuffmanTreep;

integers1,s2,i,m,start,c,f;

char*cd;

m:

=2*n-1;

HT[0].weight:

=1000000;

p:

=HT+1;

foritondo

(*p).weight:

=*w;

(*p).parent:

=(*p).lchild:

=(*p).rchild:

=0;

++p;

++w;

end{for}

foritomdo

(*p).weight=(*p).parent=(*p).lchild=(*p).rchild=

0;

forifromn+1tomdo

Select(HT,i-1,s1,s2);

HT[s1].parent:

=i;

HT[s2].parent:

HT[i].lchild:

=s1;

HT[i].rchild:

=s2;

HT[i].weight:

=HT[s1].weight+HT[s2].weight;

cd[n-1]='

\0'

;

//编码结束符

start:

=n-1;

//编码结束符位置

f:

c:

forffromHT[f].parenttof=0do

ifHT[f].lchild=c

cd[--start]:

='

0'

1'

end{else}

end{if}

end{HuffmanCoding}

源代码:

#include<

stdlib.h>

string.h>

iostream>

usingnamespacestd;

#defineinfinite50000

//定义Huffman树和Huffman编码的存储表示

//字符的频数

//双亲结点,左孩子,右孩子

voidSelect(HuffmanTreeHT,intn,int&

s1,int&

s2);

voidHuffmanCoding(HuffmanTree&

HC,int*w,intn);

voidmain()

inti,n,*w;

cout<

<

"

enterthesizeofthecode:

cin>

>

n;

endl;

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

entertheweightofthecode:

"

endl;

i<

=n;

i++)//逐个输入每个字符的出现的频数,并

用空格隔开

cin>

w[i];

HuffmanTreeHT;

HuffmanCodeHC;

HuffmanCoding(HT,HC,w+1,n);

cout<

thehuffmancodeis:

i++)

w[i]<

:

cout<

HC[i]<

}cout<

system("

pause"

〃在HuffmanTree中HT[1…n]选择parent为且weight最小的两个结点,其序号分别为s1和s2

s2)

inti;

s1=s2=0;

if(HT[i].parent==0&

&

HT[s2].weight>

HT[i].weight)s2=i;

if(HT[i].parent==0&

HT[s1].weight>

HT[i].weight)

s1=i;

〃构造Huffman树HT,并求出n个字符的Huffman编码HC

HC,int*w,intn)

if(n<

=1)return;

ints1,s2,i,m,start,c,f;

m=2*n-1;

HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));

HT[0].weight=infinite;

//将号单元置一个较大的数

for(p=HT+1,i=1;

++i,++p,++w)

(*p).weight=*w;

//将n个字符的频数送到

HT.weight[1…n]

(*p).parent=(*p).lchild=(*p).rchild=0;

//双亲孩子

初始化为

for(;

=m;

++i,++p)

(*p).weight=(*p).parent=(*p).lchild=(*p).rchild=0;

//

将HuffmanTree结点权值HT.weight[n+1…m+1](频数)及双亲孩子初始化为

for(i=n+1;

++i)//根据Huffman编码原理进行构建Huffman

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;

//从叶子到根逆向求每个字符的Huffman编码

HC=(HuffmanCode)malloc((n+1)*sizeof(char*));

//分配n个字符编码的头指针向量,注号单元未用

cd=(char*)malloc(n*sizeof(char));

//分配求编

码的工作空间

\0:

〃编码结束符

++i)//逐个字符求Huffman编码

start=n-1;

//编码结束符位置

for(c=i,f=HT[i].parent;

f!

=0;

c=f,f=HT[f].parent)//从叶

子到根逆向求编码

if(HT[f].lchild==c)

cd[--start]='

HC[i]=(char*)malloc((n-start)*sizeof(char));

//为第i个字符编码分配空间

strcpy_s(HC[i],sizeof(&

cd[start]),&

cd[start]);

free(cd);

答案2)

c语言实现:

huffman编码解码

#defineN100

编码

#defineM2*N-1

typedefchar*HuffmanCode[2*M];

//haffman

intweight;

//权值

intparent;

//父节节点

intLChild;

//左子节点

intRChild;

//右子节点

}HTNode,Huffman[M+1];

//huffman树typedefstructNode

//叶子结点的权值

charc;

//叶子结点

intnum;

//叶子结点的二进制码的长度

}WNode,WeightNode[N];

/***产生叶子结点的字符和权值***/

voidCreateWeight(charch[],int*s,WeightNodeCW,int*p)

inttag;

*p=0;

〃叶子节点个数

//统计字符出现个数,放入CW

for(i=0;

ch[i]!

='

tag=1;

for(j=0;

i;

if(ch[j]==ch[i])

tag=0;

break;

if(tag)

CW[++*p].c=ch[i];

CW[*p].weight=1;

for(k=i+1;

ch[k]!

if(ch[i]==ch[k])

CW[*p].weight++;

//权值累加

*s=i;

//字符串长度

/********仓寸建HuffmanTree********/

voidCreateHuffmanTree(Huffmanht,WeightNodew,intn){

ints1,s2;

//初始化哈夫曼树

ht[i].weight=w[i].weight;

ht[i].parent=0;

ht[i].LChild=0;

ht[i].RChild=0;

for(i=n+1;

=2*n-1;

ht[i].weight=O;

ht[i].parent=O;

ht[i].LChild=O;

ht[i].RChild=O;

jv=i_1;

if(!

ht[j].parent)

s1=j;

//找到第一个双亲不为零的结点

=i-1;

s1=ht[s1].weight>

ht[j].weight?

j:

s1;

ht[s1].parent=i;

ht[i].LChild=s1;

s2=j;

//找到第二个双亲不为零的结点

s2=ht[s2].weight>

s2;

ht[s2

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 自考

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1