完整版4+四+贪心算法+习题参考答案文档格式.docx
- 文档编号:22429003
- 上传时间:2023-02-04
- 格式:DOCX
- 页数:41
- 大小:117.56KB
完整版4+四+贪心算法+习题参考答案文档格式.docx
《完整版4+四+贪心算法+习题参考答案文档格式.docx》由会员分享,可在线阅读,更多相关《完整版4+四+贪心算法+习题参考答案文档格式.docx(41页珍藏版)》请在冰豆网上搜索。
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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 完整版 贪心 算法 习题 参考答案