计算机算法实验3 贪心算法 报告.docx
《计算机算法实验3 贪心算法 报告.docx》由会员分享,可在线阅读,更多相关《计算机算法实验3 贪心算法 报告.docx(15页珍藏版)》请在冰豆网上搜索。
计算机算法实验3贪心算法报告
《算法设计与分析》
姓名:
班级:
学号:
课题:
贪心算法
指导教师:
2014/1/6
目录
1实验目的与要求1
2实验内容1
2.1基本题一:
多机调度问题1
2.1.1问题概述1
2.1.2实验截图1
2.2提高题一:
用贪心算法求解最小生成树2
2.2.1问题概述2
2.2.2实验截图2
2.3提高题二:
汽车加油问题3
2.3.1问题概述3
2.3.2实验截图3
3实验心得4
代码附后面
1实验目的与要求
1、熟悉多机调度问题的算法
2、初步掌握贪心算法
3、熟悉贪心算法的基本原理与适用范围
4、使用贪心算法编程,求解最小生成树问题
5、掌握汽车加油问题的算法
2实验内容
2.1基本题一:
多机调度问题
2.1.1问题概述
要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。
约定,每个作业均可在任何一台机器上加工处理,但未完工前不允许中断处理。
作业不能拆分成更小的子作业。
提示:
1、把作业按加工所用的时间从大到小排序
2、如果作业数目比机器的数目少或相等,则直接把作业分配下去
3、 如果作业数目比机器的数目多,则每台机器上先分配一个作业,如下的作业分配时,是选那个表头上s最小的链表加入新作业。
2.1.2实验截图
按照书本例题数据,7个作业分给3台机器,完成时间为17,实验结果如下:
2.2提高题一:
用贪心算法求解最小生成树
2.2.1问题概述
任选一种贪心算法(Prim或Kruskal),求解最小生成树。
对算法进行描述和复杂性分析。
编程实现,并给出测试实例
2.2.2实验截图
算法为Kruskal,选用书本例题数据,六个定点,十条边,求解结果如下:
2.3提高题二:
汽车加油问题
2.3.1问题概述
一辆汽车加满油后可以行驶N千米。
旅途中有若干个加油站。
若要使沿途的加油次数最少,设计一个有效的算法,指出应在那些加油站停靠加油。
并证明你的算法能产生一个最优解。
把两加油站的距离放在数组中,a[1..n]表示从起始位置开始跑,经过n个加油站,a[k]表示第k-1个加油站到第k个加油站的距离。
汽车在运行的过程中如果能跑到下一个站则不加油,否则要加油。
2.3.2实验截图
输入3代表加油站段目,50代表加油后最大行驶距离结果如下:
再换一个例子:
3实验心得
这次算法实验的主要内容是贪心算法的使用,包括多机调度问题,最小生成树问题(采用Kruskal算法),汽车加油问题。
贪心算法是一种对某些求最优解问题的更简单、更迅速的设计技术。
用贪婪法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间,它采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。
贪心算法是算法的重要内容之一,可以高效地解决许多问题。
采用贪心算法会比动态规划高效方便,如果都能解决某个问题的话。
现在我学习贪心算法的时间还不长,理解还很浅显,以后要多加练习,这样才能做到熟练运用。
基本题一:
多机调度问题
#include
usingnamespacestd;
#defineN10
typedefstructnode{
intID,time;//作业所需时间
}jobnode;
typedefstructNode{
intID,avail;//ID机器编号avail每次作业的初始时间
}manode;
manodemachine[N];jobnodejob[N];/*
找出下个作业执行机器*/
manode*Find_min(manodea[],intm){
manode*temp=&a[0];
for(inti=1;iif(a[i].availavail)
temp=&a[i];
}
returntemp;
}/*
对作业时间由大到小进行排序*/
voidSort(jobnodet[],intn){
jobnodetemp;
for(inti=0;ifor(intj=n-1;j>i;j--){
if(job[j].time>job[j-1].time){
temp=job[j];
job[j]=job[j-1];
job[j-1]=temp;
}
}
}
voidmain(){
intn,m,temp,i;manode*ma;
printf("输入作业数目(作业编号按输入顺序处理)\n");
cin>>n;
printf("输入相应作业所需处理时间:
\n");for(i=0;icin>>job[i].time;job[i].ID=i+1;
}
printf("输入机器数目(机器编号按输入顺序处理)\n");
cin>>m;
for(i=0;i{
machine[i].ID=i+1;machine[i].avail=0;
}
putchar('\n');if(n<=m){
printf("为每个作业分配一台机器,可完成任务!
\n");return;
}
Sort(job,n);
for(i=0;ima=Find_min(machine,m);
printf("将机器:
M%d从%d----->%d的时间段分配给作业:
%d\n",
ma->ID,ma->avail,ma->avail+job[i].time,job[i].ID);
ma->avail+=job[i].time;}
temp=machine[0].avail;for(i=1;iif(machine[i].avail>temp)temp=machine[i].avail;
}
putchar('\n');
printf("该批作业处理完成所需加工时间为:
%d\n",temp);
}
2提高题一:
用贪心算法求解最小生成树
/*****************************************************
该程序用贪心算法来求解最小生成树问题
采用贪婪准则:
每次选择边权值最小边。
如果该边加入后
不构成环,则加入。
*******************************************************/
#include
#include
usingnamespacestd;
intconstCNST_Numgrphedge=100;
structTTreeEdge//最小生成树的边类型
{
longv1,v2;//边的起点与终点编号
floatweight;//边权
};
/**************************
全局变量
***************************/
intty=0;//纪录返回边的个数(作为引用参数中数组的下标)
/******************************************************
该函数通过贪心算法求出最小生成树,返回值为最小生成树中
的边(起点与终点编号与边权),通过引用参数edge返回值
*******************************************************/
voidminspanningTree(TTreeEdgetreeedge[],intn,inte,TTreeEdge*edge)
{
/********************************************
treeedge[]为图最初的起点与终点编号与边权
n为顶点数
e为边数
引用参数edge[]为最小最小生成树中的边(起点
与终点编号与边权)
********************************************/
inti,j,u,v,p;
inttempa[CNST_Numgrphedge];//临时数组,该数组存储连通变量
longtemp1,temp2;//改进的冒泡排序中所用参数
floattemp3;//改进的冒泡排序中所用参数
intm,kk;//改进的冒泡排序中所用参数
/**********************************************
按照边的权值从小到大排序(采用改进的冒泡排序)
***********************************************/
m=e-1;
while(m>0)
{
kk=0;
for(j=0;jif(treeedge[j].weight>treeedge[j+1].weight)
{
temp1=treeedge[j].v1;
treeedge[j].v1=treeedge[j+1].v1;
treeedge[j+1].v1=temp1;
temp2=treeedge[j].v2;
treeedge[j].v2=treeedge[j+1].v2;
treeedge[j+1].v2=temp2;
temp3=treeedge[j].weight;
treeedge[j].weight=treeedge[j+1].weight;
treeedge[j+1].weight=temp3;
kk=j;
}
m=kk;
}//while
/******************************************
初始化临时数组,该数组存储连通变量
*******************************************/
for(i=0;itempa[i]=i;
p=1;
for(j=0;p{
u=treeedge[j].v1;//边的起点
v=treeedge[j].v2;//边的终点
/*************************************************
如果起点与终点的连通变量不相等,则加入,将这条边
的起点与终点编号与边权存入引用参数edge中,并改变
临时数组的值
************************************************/
if(tempa[u]!
=tempa[v])
{
edge[ty].v1=u;//将选中边的起点编号存入引用参数edge中
edge[ty].v2=v;//将选中边的终点编号存入引用参数edge中
edge[ty].weight=treeedge[j].weight;//将选中边的边权存入引用参数edge中
ty++;//边数加1
p++;//边数加1
for(i=0;iif(tempa[i]==tempa[v])
tempa[i]=tempa[u];//改变临时数组的值
}
}
}
voidmain()
{
inti,e,n;
intb;
intAgain=0;
charyn;
TTreeEdgetreeedge[CNST_Numgrphedge];
TTreeEdgeedge[CNST_Numgrphedge];
cout<<"****************************************************"<cout<<"该程序用贪心算法来求解最小生成树问题。
"<cout<<"采用贪婪准则:
每次选择边权值最小边。
"<cout<<"如果该边加入后不构成环,则加入。
"<cout<<"****************************************************"<while(!
Again)
{
cout<<"----------------------------------------------------"<cout<<"请输入图的顶点数:
";
cin>>n;
/****************************************
判断输入图的顶点数的合法性!
****************************************/
b=0;
while(!
b)
{
if(n<3)
{
cout<<"输入错误!
顶点数不能小于3个!
"<cout<<"请重新输入图的顶点数:
";
cin>>n;
}
else
b=1;
}//while
cout<<"请输入图的边数(最多"<";
cin>>e;
/****************************************
判断输入图的边数的合法性!
****************************************/
b=0;
while(!
b)
{
if(e>(n*(n-1))/2)
{
cout<<"输入错误!
顶点数为"<"<cout<<"请重新输入图的边数(最多"<";
cin>>e;
}
else
b=1;
}//while
cout<<"请输入图的各条边的起点位置、终点位置、边权(起/终点位置用数字输入):
"<for(i=0;i{
cin>>treeedge[i].v1>>treeedge[i].v2>>treeedge[i].weight;
/********************************************************
判断输入图的各条边的起点位置、终点位置、边权的合法性!
*********************************************************/
b=0;
while(!
b)
{
if(treeedge[i].v1<0|treeedge[i].v2<0|treeedge[i].weight<0)
{
cout<<"输入错误!
边的起点位置、终点位置、边权不能小于0!
"<cout<<"请重新输入该条边的起点位置、终点位置、边权(起/终点位置用数字输入):
"<cin>>treeedge[i].v1>>treeedge[i].v2>>treeedge[i].weight;
}
else
b=1;
}//while
}
/********************
调用函数
*********************/
minspanningTree(treeedge,n,e,edge);
/*******************************************************
输出引用参数edge[]中存储的边的起点位置、终点位置、边权
********************************************************/
cout<<"最小生成树所包含的边为:
(依次为边的起点位置、终点位置、边权)"<for(i=0;icout</********************************************
是否进行下一个最小生成树问题的求解
*********************************************/
cout<<"\n继续进行另一个最小生成树问题的解答吗?
(Y/N)";
cin>>yn;
if(yn=='Y'||yn=='y')
Again=0;
else
if(yn=='N'||yn=='n')
Again=1;
elsebreak;
}
}
3提高题二:
汽车加油问题
#include
usingnamespacestd;
intmain()
{
intOilStationNum;//加油站的数目
intMaxDist;//汽车加满油以后行驶的最大距离
intDiscOfCar;//汽车一次加油后已经行驶的距离
intCount;
int*OilStationDist;
printf("请输入加油站的段数(用整数表示):
");
cin>>OilStationNum;
printf("汽车加满油以后行驶的最大距离(用整数表示):
");
cin>>MaxDist;
OilStationDist=newint[OilStationNum-1];
printf("请输入各加油站之间的距离(假设不能有环路):
\n");
for(Count=0;Count<=OilStationNum-1;)
{
cin>>OilStationDist[Count];
if(OilStationDist[Count]<=MaxDist)Count++;
else
printf("你输入的加油站之间的距离大于汽车加满油以后行驶的最大距离,请重新输入当前距离!
\n");
}
DiscOfCar=0;
Count=0;
while
(1)
{
if(DiscOfCar<=MaxDist)
{
DiscOfCar+=OilStationDist[Count];
Count++;
}
else
{
Count--;
printf("当前汽车需要在%d号加油站处加油,此时汽车行驶了%d公里\n",Count,DiscOfCar-OilStationDist[Count]);
DiscOfCar=0;
}
if(Count>OilStationNum)
{
//printf("当前汽车到达终点,此时汽车距上一次加油行驶了%d公里\n",DiscOfCar);
break;
}
}
return0;
}