算法设计与分析实验四.docx

上传人:b****4 文档编号:3658625 上传时间:2022-11-24 格式:DOCX 页数:17 大小:84.10KB
下载 相关 举报
算法设计与分析实验四.docx_第1页
第1页 / 共17页
算法设计与分析实验四.docx_第2页
第2页 / 共17页
算法设计与分析实验四.docx_第3页
第3页 / 共17页
算法设计与分析实验四.docx_第4页
第4页 / 共17页
算法设计与分析实验四.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

算法设计与分析实验四.docx

《算法设计与分析实验四.docx》由会员分享,可在线阅读,更多相关《算法设计与分析实验四.docx(17页珍藏版)》请在冰豆网上搜索。

算法设计与分析实验四.docx

算法设计与分析实验四

实验四:

贪心法

一、实验目的

1、掌握贪心算法的基本设计思想与原则

2、运用贪心法求解经典问题(验证性实验)

二、实验原理

1、优化问题

有n个输入,而它的解就由这n个输入满足某些事先给定的约束条件的某个子集组成,而把满足约束条件的子集称为该问题的可行解。

可行解一般来说是不唯一的。

那些使目标函数取极值(极大或极小)的可行解,称为最优解。

2、贪心法求优化问题

算法思想:

在贪心算法中采用逐步构造最优解的方法。

在每个阶段,都作出一个看上去最优的决策(在一定的标准下)。

决策一旦作出,就不可再更改。

作出贪心决策的依据称为贪心准则(greedycriterion)。

3、一般方法

1)根据题意,选取一种量度标准。

2)按这种量度标准对这n个输入排序

3)依次选择输入量加入部分解中。

如果当前这个输入量的加入,不满足约束条件,则不把此输入加到这部分解中。

procedureGREEDY(A,n)/*贪心法一般控制流程*/

//A(1:

n)包含n个输入//

solutions←φ//将解向量solution初始化为空/

fori←1tondo

x←SELECT(A)

ifFEASIBLE(solution,x)

thensolutions←UNION(solution,x)

endif

repeat

return(solution)

endGREEDY

三、实验要求

1、用C++/C完成算法设计和程序设计并上机调试通过。

2、撰写实验报告,提供实验结果和数据。

3、分析算法,要求给出具体的算法分析结果,包括时间复杂度和空间复杂度,并简要给出算法设计小结和心得。

四、实验内容

1、哈夫曼编码

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

设需要编码的字符集为{d1,d2,…,dn},它们出现的频率为{w1,w2,…,wn},以d1,d2,…,dn作为叶子结点,w1,w2,…,wn作为叶子结点的权值,构造一棵哈夫曼编码树,规定哈夫曼编码树的左分支代表0,右分支代表1,则从根结点到每个叶子结点所经过的路径组成的0和1的序列便为该叶子结点对应字符的编码即为哈夫曼编码。

考虑到哈夫曼树中共有2n-1个结点,并且进行n-1次合并操作,为了便于选取根结点权值最小的二叉树以及合并操作,设置一个数组huffTree[2n-1]保存哈夫曼树中各结点的信息,数组元素的结点结构如下图所示。

 

将数组元素的结点类型定义为:

structelement

{

doubleweight;//字符出现的概率为实数

intlchild,rchild,parent;

};

建立哈夫曼树的算法如下:

 

Select函数用来在数组huffTree中选取两个权值最小的根结点,请读者自行完成。

根据已建立的哈夫曼树,规定哈夫曼树的左分支代表0,右分支代表1,则哈夫曼编码即是从根结点到每个叶子结点所经过的路径组成的0和1的序列。

算法如下:

 

2、背包问题

贪心算法:

procedureKNAPSACK(P,W,M,X,n)

//P(1:

n)和W(1;n)分别含有按

P(i)/W(i)≥P(i+1)/W(i+1)排序的n件物品的效益值

和重量。

M是背包的容量大小,而x(1:

n)是解向量

realP(1:

n),W(1:

n),X(1:

n),M,cu;

integeri,n;

X←0//将解向量初始化为零

cu←M//cu是背包剩余容量

fori←1tondo

ifW(i)>cuthenexitendif

X(i)←1

cu←cu-W(i)

repeat

ifi≤nthenX(i)←cu/W(i)

endif

endGREEDY-KNAPSACK

procedureprim(G,)

status←“unseen”//T为空

status[1]←“treenode”//将1放入T

foreachedge(1,w)do

status[w]←“fringe”//找到T的邻接点

dad[w]←1;//w通过1与T建立联系

dist[w]←weight(1,w)//w到T的距离

repeat

whilestatus[t]≠“treenode”do

pickafringeuwithmindist[w]//选取到T最近的节点

status[u]←“treenode”

foreachedge(u,w)do

修改w和T的关系

repeat

repeat

3、最小生成树的prim算法

PrimMST(G,T,r){

 //求图G的以r为根的MST,结果放在T=(U,TE)中

   InitCandidateSet(…);//初始化:

设置初始的轻边候选集,并置T=({r},¢)

   for(k=0;k

       (u,v)=SelectLiShtEdge(…);//选取轻边(u,v);

        T←T∪{(u,v)};//扩充T,即(u,v)涂红加入TE,蓝点v并人红点集U

       ModifyCandidateSet(…);//根据新红点v调整候选轻边集

     } 

  }

4、最短路径问题

最短路径问题是图论研究中的一个经典算法问题,旨在寻找图中两结点之间的最短路径。

给定带权有向图G=(V,E),其中每条边的权是非负实数。

另外,还给定V中的一个顶点,称为源。

现在要计算从源到所有其它各顶点的最短路长度。

这里路的长度是指路上各边权之和。

这个问题通常称为单源最短路径问题。

 Dijkstra算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径。

主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。

创建两个表,OPEN,CLOSE。

  OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。

  1)访问路网中距离起始点最近且没有被检查过的点,把这个点放入OPEN组中等待检查。

  2)从OPEN表中找出距起始点最近的点,找出这个点的所有子节点,把这个点放到CLOSE表中。

  3)遍历考察这个点的子节点。

求出这些子节点距起始点的距离值,放子节点到OPEN表中。

  4)重复第2和第3步,直到OPEN表为空,或找到目标点。

算法描述:

  

  1)置集合S={2,3,...n},数组d

(1)=0,d(i)=W1->i(1,i之间存在边)or+无穷大(1.i之间不存在边)

  2)在S中,令d(j)=min{d(i),i属于S},令S=S-{j},若S为空集则算法结束,否则转3)

  3)对全部i属于S,如果存在边j->i,那么置d(i)=min{d(i),d(j)+Wj->i},转2)

  Dijkstra算法思想为:

设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径,就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。

在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。

此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

算法具体步骤:

 

  

(1)初始时,S只包含源点,即S=,v的距离为0。

U包含除v外的其他顶点,U中顶点u距离为边上的权(若v与u有边)或)(若u不是v的出边邻接点)。

  

(2)从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

  (3)以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u(uU)的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

  (4)重复步骤

(2)和(3)直到所有顶点都包含在S中。

5、多机调度问题

要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。

约定,每个作业均可在任何一台机器上加工处理,但未完工前不允许中断处理。

作业不能拆分成更小的子作业。

步骤:

1)把作业按加工所用的时间从大到小排序

2)如果作业数目比机器的数目少或相等,则直接把作业分配下去

3)如果作业数目比机器的数目多,则每台机器上先分配一个作业,如下的作业分配时,是选那个表头上s最小的链表加入新作业。

五、参考程序

2、背包问题贪心算法

#include

structgoodinfo

{

floatp;//物品效益

floatw;//物品重量

floatX;//物品该放的数量

intflag;//物品编号

};//物品信息结构体

voidInsertionsort(goodinfogoods[],intn)

{

intj,i;

for(j=2;j<=n;j++)

{

goods[0]=goods[j];

i=j-1;

while(goods[0].p>goods[i].p)

{

goods[i+1]=goods[i];

i--;

}

goods[i+1]=goods[0];

}

}//按物品效益,重量比值做升序排列

voidbag(goodinfogoods[],floatM,intn)

{

floatcu;

inti,j;

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

goods[i].X=0;

cu=M;//背包剩余容量

for(i=1;i

{

if(goods[i].w>cu)//当该物品重量大与剩余容量跳出

break;

goods[i].X=1;

cu=cu-goods[i].w;//确定背包新的剩余容量

}

if(i<=n)

goods[i].X=cu/goods[i].w;//该物品所要放的量

for(j=2;j<=n;j++)

{

goods[0]=goods[j];

i=j-1;

while(goods[0].flag

{

goods[i+1]=goods[i];

i--;

}

goods[i+1]=goods[0];

}

cout<<"最优解为:

"<

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

{

cout<<"第"<

";

cout<

}

}

voidmain()

{

cout<<"|--------运用贪心法解背包问题---------|"<

cout<<"|-------------------------------------|"<

intj;

intn;

floatM;

goodinfo*goods;//定义一个指针

while(j)

{

cout<<"请输入物品的总数量:

";

cin>>n;

goods=newstructgoodinfo[n+1];//

cout<<"请输入背包的最大容量:

";

cin>>M;

cout<

inti;

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

{goods[i].flag=i;

cout<<"请输入第"<

";

cin>>goods[i].w;

cout<<"请输入第"<

";

cin>>goods[i].p;

goods[i].p=goods[i].p/goods[i].w;//得出物品的效益,重量比

cout<

}

Insertionsort(goods,n);

bag(goods,M,n);

cout<<"press<1>torunagian"<

cout<<"press<0>toexit"<

cin>>j;

}

}

3、最小生成树的prim算法

#include

#include

#include

#defineINFINITYINT_MAX

#defineMAX_VERTEX_NUM20

typedefintVRType;

typedefintInfoType;

typedefcharVerTexType;

typedefstructArcCell

{

VRTypeadj;

InfoType*info;

}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedefstruct

{

VerTexTypevexs[MAX_VERTEX_NUM];

AdjMatrixarcs;

intvexnum,arcnum;

}MGraph;

typedefstruct

{

VerTexTypeadjvex;

VRTypelowcost;

}closedge[MAX_VERTEX_NUM];

voidCreateGraph(MGraph&G);

voidMiniSpanTree_PRIM(MGraphG,VerTexTypeu);

intLocateVex(MGraphG,VerTexTypeu);

intminimum(closedgeclose);

voidmain(void)

{

inti,j;

MGraphG;

CreateGraph(G);

for(i=0;i

{

for(j=0;j

{

cout<

cout<<"";

}

cout<

}

MiniSpanTree_PRIM(G,'a');

}

voidCreateGraph(MGraph&G)

{

intweigh;

inti,j=0,k=0;

charhand,tide;

cout<<"inputthenumberforvexnumandarcnum:

";

cin>>G.vexnum>>G.arcnum;

for(i=0;i

{

for(j=0;j

G.arcs[i][j].adj=88;

}

cout<

cout<<"input"<

";

for(i=0;i

cin>>G.vexs[i];

cout<

cout<<"input"<

"<

j=0;

k=0;

for(i=0;i

{

cout<

";

cin>>hand;

cin>>tide;

cin>>weigh;

while(hand!

=G.vexs[j])

j++;

while(tide!

=G.vexs[k])

k++;

G.arcs[j][k].adj=weigh;

G.arcs[k][j].adj=weigh;

j=0;

k=0;

cout<

}

}

voidMiniSpanTree_PRIM(MGraphG,VerTexTypeu)

{

inti,j,k=0;

closedgeclose;

k=LocateVex(G,u);

for(j=0;j

{

if(j!

=k)

{

close[j].adjvex=G.vexs[k];

close[j].lowcost=G.arcs[k][j].adj;

}

}

close[j].lowcost=88;

close[j].adjvex='\0';

close[k].lowcost=0;

close[k].adjvex=u;

for(i=1;i

{

k=minimum(close);

cout<

cout<<"---->";

cout<

cout<

close[k].lowcost=0;

for(j=0;j

{

if(G.arcs[k][j].adj

{

close[j].adjvex=G.vexs[k];

close[j].lowcost=G.arcs[k][j].adj;

}

}

}

}

intLocateVex(MGraphG,VerTexTypeu)

{

intk=0;

while(G.vexs[k++]==u)

returnk-1;

return0;

}

intminimum(closedgeclose)

{

intj1=0,client=88,j2;

while(close[j1].adjvex!

='\0')

{

if(client>close[j1].lowcost&&close[j1].lowcost!

=0)

{

client=close[j1].lowcost;

j2=j1;

}

j1++;

}

returnj2;

}

4、最短路径问题

#include

  #include

  usingnamespacestd;

  constintMaxNum=1000000;//边权最大值

  intn;//节点数目

  intdist[501];//到节点1的最短路径值

  boolstate[501];//节点被搜索过状态指示

  intdata[501][501];//邻接矩阵

  //查找权值最小的节点

  intfindmin()

  {

  intminnode=0,min=MaxNum;

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

  if((dist[i]

state[i]))

  {

  min=dist[i];

  minnode=i;

  }

  returnminnode;

  }

  intmain()

  {

  ifstreamin("dijkstra.in");

  ofstreamout("dijkstra.out");

  memset(state,0,sizeof(state));

  in>>n;

  for(intp=1;p<=n;p++)

  for(intq=1;q<=n;q++)

  {

  in>>data[p][q];

  if(data[p][q]==0)data[p][q]=MaxNum;

  }

  //初始化

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

  dist[i]=data[1][i];

  state[1]=true;

  intdone=1;

  while(done

  {

  intnode=findmin();

  if(node!

=0)

  {

  done++;//找到的点的数目加1

  state[node]=true;//标记已经找到了从节点1到节点node的最短路径

  for(inti=1;i<=n;i++)//更新还没有找到的点的路径值

  if((dist[i]>dist[node]+data[node][i])&&(!

state[i]))

  dist[i]=dist[node]+data[node][i];

  }

  elsebreak;

  }

  for(intk=1;k<=n;k++)

  {

  if(dist[k]==MaxNum)

  out<<-1;

  else

  out<

  if(k==n)

  out<

  else

  out<<"";

  }

  in.close();

  out.close();

  return0;

  }

5、多机调度问题

typedefstructJob

{

   intID;//作业号

   inttime;//作业所花费的时间

}Job;

 

typedefstructJobNode//作业链表的节点

{

   intID;

   inttime;

   JobNode*next;

}JobNode,*pJobNode;

 

typedefstructHeader //链表的表头

{

   ints;

   pJobNodenext;

}Header,pHeader;

 

intSelectMin(Header*M,intm)

{

   intk=0;

   for(inti=1;i

   {

      if(M[i].s

   }

   returnk;

}

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

当前位置:首页 > 求职职场 > 简历

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

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