实验三 贪心算法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验三贪心算法
一、实验目的与要求
1、熟悉多机调度问题的算法;
2、初步掌握贪心算法;
二、实验题
要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。

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

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

三、实验提示
1、把作业按加工所用的时间从大到小排序
2、如果作业数目比机器的数目少或相等,则直接把作业分配下去
3、如果作业数目比机器的数目多,则每台机器上先分配一个作业,如下的作业分配时,是选那个表头上s最小的链表加入新作业。

# include <iostream>
# include <iomanip>
using namespace std;
typedef struct Job //作业
{
int ID;
int time;
}Job;
typedef struct JobNode //作业链表的节点
{
int ID;
int time;
JobNode *next;
}JobNode,*pJobNode;
typedef struct Header //链表的表头
{
int s; //处理机上的时间;
JobNode *next;
}Header,pHeader;
int main()
{
void QuickSort(Job *job,int left,int right); //将job时间排序
void outSort(Job *job,int n); //输出排序
void display(Header *M,int m); //输出每个每台机器处理的工作
序号数
int SelectMin(Header *M,int m); //分配作业时选取机器函数;
void solve(Header *head,Job*job,int n,int m); //作业分配函数;
int m,n;
cout<<"\t\t《多机调度问题》\n";
cout<<"请输入机器台数m:";
cin>>m;
Header *head=new Header [m]; //动态构建数组结构体,用于记录机器的作业时间;
cout<<"请输入作业个数n:";
cin>>n;
Job *job=new Job [n]; //动态构建作业的数组结构体;
cout<<"\n请按序号输入每个作业调度所需时间time:";
for(int i=0;i<n;i++)
{
cin>>job[i].time;
job[i].ID=i;
}
QuickSort(job,0,n-1); //作业排序
outSort(job,n); //输出排序
solve(head,job,n,m); //作业分配
display(head,m); //输出分配
cout<<endl<<endl;
return 0;
}
int SelectMin(Header* M,int m) //选择s最小的机器序号k;
{
int k=0;
for(int i=1;i<m;i++)
{
if(M[i].s<M[k].s)
k=i; //k记录S最小的序号;
}
return k;
}
void QuickSort(Job *job,int left,int right) //小到大,排序
{
int middle=0,i=left,j=right;
Job itemp;
middle=job[(left+right)/2].time;
do
{
while((job[i].time>middle)&&(i<right))
i++;
while((job[j].time<middle)&&(j>left))
j--;
if(i<=j)
{
itemp=job[j];
job[j]=job[i];
job[i]=itemp;
i++;
j--;
}
}while(i<=j);
if(left<j)
QuickSort(job,left,j);
if(right>i)
QuickSort(job,i,right);
}
void display(Header *M,int m) //作业分配输出函数;
{
JobNode *p;
for(int i=0;i<m;i++)
{
cout<<"\n第"<<i<<"台机器上处理的工作序号:";
if(M[i].next==0)
continue;
p=M[i].next;
do{
cout<<p->ID<<' ';
p=p->next;
}while(p!=0);
}
}
void outSort(Job *job,int n) //作业时间由大到小排序后输出函数;{
cout<<"\n按工作时间由大到小为:\n时间:\t";
for(int i=0;i<n;i++)
cout<<setw(4)<<job[i].time;
cout<<"\n序号:\t";
for( i=0;i<n;i++)
cout<<setw(4)<<job[i].ID;
}
void solve(Header *head,Job*job,int n,int m) //作业分配函数;{
int k;
for(int i=0;i<m&&i<n;i++)
{
JobNode *jobnode=new JobNode;
jobnode->time=job[i].time;
jobnode->ID=job[i].ID;
jobnode->next=0;
head[i].s=jobnode->time;
head[i].next=jobnode;
}
if(i<=m) //n<m的情况续处理;
{
for(i;i<m;i++)
{
head[i].s=0;
head[i].next=0;
}
}
if(n>m)
{
for(i;i<n;i++)
{
JobNode *p;
JobNode *jobnode=new JobNode;
jobnode->time=job[i].time;
jobnode->ID=job[i].ID;
jobnode->next=0;
k=SelectMin(head,m);
p=head[k].next;
head[k].s+=jobnode->time;
while(p->next!=0)
p=p->next;
p->next=jobnode;
}
}
}
运行结果:
提高题一:用贪心算法求解最小生成树
一、实验要求与目的
1、熟悉贪心算法的基本原理与适用范围。

2、使用贪心算法编程,求解最小生成树问题。

二、实验内容
1、任选一种贪心算法(Prim或Kruskal),求解最小生成树。

对算法进行描述和复杂性分析。

编程实现,并给出测试实例
#include <stdio.h>
#include <limits.h>
//图中顶点个数
#define V 5
//未在mstSet中的点的集合中,找出最小key的点
int minKey(int key[], bool mstSet[])
{
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (mstSet[v] == false && key[v] < min)
min = key[v], min_index = v;
return min_index;
}
// 打印MST
int printMST(int parent[], int n, int graph[V][V])
{
printf("Edge Weight\n");
for (int i = 1; i < V; i++)
printf("%d - %d %d \n", parent[i], i, graph[i][parent[i]]);
return 0;
}
// Prim算法
void primMST(int graph[V][V])
{
int parent[V]; // 保持MST信息
int key[V]; // 所有顶点的代价值
bool mstSet[V]; //当前包含在MST中点的集合
// 初始为无穷大
for (int i = 0; i < V; i++)
key[i] = INT_MAX, mstSet[i] = false;
key[0] = 0; //
parent[0] = -1; // 第一个作为树的根。

// MST 有V的顶点
for (int count = 0; count < V-1; count++)
{
int u = minKey(key, mstSet);
// 添加u到MST Set
mstSet[u] = true;
//更新和u相连的顶点的代价
for (int v = 0; v < V; v++)
if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v]) parent[v] = u, key[v] = graph[u][v];
}
// 打印生成的MST
printMST(parent, V, graph);
}
int main()
{
/* 创建以下的图
2 3
(0)--(1)--(2)
| / \ |
6| 8/ \5 |7
| / \ |
(3)-------(4)
9 */
int graph[V][V] = {{0, 2, 0, 6, 0},
{2, 0, 3, 8, 5},
{0, 3, 0, 0, 7},
{6, 8, 0, 0, 9},
{0, 5, 7, 9, 0},
};
// Print the solution
primMST(graph);
return 0;
}
运行结果:
时间复杂度
这里记顶点数v,边数e
时间复杂度:O(v^2). 如果使用链接表存储的方式并使用堆,复杂度可以为:O(elog2v)提高题二:汽车加油问题
一、实验目的与要求
1、掌握汽车加油问题的算法;
2、进一步掌握贪心算法;
二、实验题
一辆汽车加满油后可以行驶N千米。

旅途中有若干个加油站。

若要使沿途的加油次数最少,设计一个有效的算法,指出应在那些加油站停靠加油。

并证明你的算法能产生一个最优解。

三、实验提示
把两加油站的距离放在数组中,a[1..n]表示从起始位置开始跑,经过n个加油站,a[k]表示
第k-1个加油站到第k个加油站的距离。

汽车在运行的过程中如果能跑到下一个站则不加油,否则要加油。

(算法略)
#include <stdio.h>
#define N 1000
int greedy(int d[],int n,int k)
{
int num = 0;
int i=0;
int s=0;
for( i = 0;i < k;i++)
{
if(d[i] > n)
{
printf("no solution\n");
return 0;
}
}
for( i = 0,s = 0;i < k;i++)
{
s += d[i];
if(s > n)
{
num++;
s = d[i];
}
}
printf("%d\n",num);
return 1;
}
void main()
{
int i,n,k;
int d[N];
printf("请输入汽车可行驶:\n");
scanf("%d",&n);
printf("加油站的个数:\n");
scanf("%d",&k);
for(i=0;i<k+1;i++)
{
printf("请输入第%d段路的长度: ",i+1);
scanf("%d",&d[i]);
fflush(stdin);
}
greedy(d,n,k+1);
}
运行结果:
四、实验总结
本次实验让我们熟练的掌握了贪心算法的两个重要的性质:最优子结构性质和贪心选择性质。

我们只有不断的练习和实验,才能更好的掌握贪心算法,知道贪心算法的优缺点,在什么情况下使用贪心算法才能更好的发挥它的作用。

相关文档
最新文档