实验二贪心算法的应用一、实验目的1.掌握贪心算法的基本概念和两个基本要素2.熟练掌握贪心算法解决问题的基本步骤。
3.学会利用贪心算法解决实际问题。
二、实验内容1.问题描述:题目二:会场安排问题假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。
设计一个有效的贪心算法来进行安排。
试编程实现对于给定的k个待安排活动,计算使用的最少会场。
输入数据中,第一行是k的值,接下来的k行中,每行有2个正整数,分别表示k个待安排活动的开始时间和结束时间,时间以0点开始的分钟计。
输出为最少的会场数。
输入数据示例51 2312 2825 3527 8036 50输出数据3三、算法分析Stept1:输入各个活动的开始时间(s)和结束时间(e),初始化各活动的会场号。
Step2:按活动的开始时间和活动时间排序,s最早(第一优先级)和持续时间最短(第二优先级)的活动排在最前。
Step3:执行贪婪算法,即s最早和持续时间最短的优先安排会场,并记录会场号,其余活动的s大于或等于已安排活动的e的安排在同一会场,若某活动的s小于安排活动的e,则安排在另一会场,记录会场号,依次循环,直到所有活动均被安排。
Step4:统计会场号数,输出。
时间复杂度:O(n)算法时间:O(nlogn)核心算法:void swap(Active &a,Active&b){Active t;t=a;a=b;b=t;}//活动时间排序for(i=1;i<=k;i++){for(j=i;j<=k;j++){if(a[i].s>a[j].s)swap(a[i],a[j]);if(a[i].s==a[j].s){if(a[i].e>a[j].e)swap(a[i],a[j]);}}}四、程序调试及运行结果分析五、源代码#include<iostream>using namespace std;#define M 50 //最大活动数struct Active{int s;//开始时间int e;//结束时间int no;//预安排会场号}a[M];//两元素交换位置void swap(Active &a,Active&b){Active t;t=a;a=b;b=t;}void main(){int k;inti,j;cout<<"输入待安排活动数:"<<endl;cin>>k;cout<<"输入待安排活动的开始时间和结束时间:"<<endl;//输入活动时间for(i=1;i<=k;i++){cin>>a[i].s>>a[i].e;a[i].no=0;}//活动时间排序for(i=1;i<=k;i++){for(j=i;j<=k;j++){if(a[i].s>a[j].s)swap(a[i],a[j]);if(a[i].s==a[j].s){if(a[i].e>a[j].e)swap(a[i],a[j]);}}}int sum=1;//使用的会场数初始化int n;a[1].no=sum;for(i=2;i<=k;i++){for(n=1;n<i;n++){if(a[n].no!=0&&a[n].e<=a[i].s){a[i].no=a[n].no;a[n].no=0;//已经安排过的活动就不再比较break;}}if(n==i){sum+=1;a[i].no=sum;}}cout<<"输出最少会场数:\n"<<sum<<endl;system("pause");}2.问题描述:题目四:汽车加油问题一辆汽车加满油后,可行使n千米。
旅途中有若干个加油站。
若要使沿途加油次数最少,设计一个有效算法,对于给定的n和k个加油站位置,指出应在哪些加油站停靠加油才能使加油次数最少。
输入数据中,第一行有2个正整数,分别表示汽车加满油后可行驶n千米,且旅途中有k个加油站。
接下来的1行中,有k+1个整数,表示第k个加油站与第k-1个加油站之间的距离。
第0个加油站表示出发地,汽车已加满油。
第k+1个加油站表示目的地。
输出为最少的加油次数,如果无法到达目的地,则输出“No Solution”。
实验提示:把两加油站的距离放在数组中,a[1..k]表示从起始位置开始跑,经过k个加油站,a[i]表示第i-1个加油站到第i个加油站的距离。
汽车在运行的过程中如果能跑到下一个站则不加油,否则要加油。
输入数据示例7 71 2 3 4 5 1 6 6输出数据4三、算法分析对于这个问题有以下几种情况:(前提:行驶前车里加满油):设加油次数为k,每个加油站间距离为a[i];(i=0,1,2,3……n)1.始点到终点的距离小于N,则加油次数k=0;2.始点到终点的距离大于N,A.加油站间的距离相等,即a[i]=a[j]=L=N,则加油次数最少k=n;B.加油站间的距离相等,即a[i]=a[j]=L>N,则不可能到达终点;C.加油站间的距离相等,即a[i]=a[j]=L<N,则加油次数k=n/N(n%N==0)或k=[n/N]+1(n%N!=0);D.加油站间的距离不相等,即a[i]!=a[j],则加油次数k由于汽车是由始向终点方向开的,最大的麻烦就是不知道在哪个加油站加油可以使既可以到达终点又可以使我们加油次数最少。
提出问题是解决的开始.为了着手解决遇到的困难,取得最优方案。
可以假设不到万不得已不加油,即除非油箱里的油不足以开到下一个加油站,才加一次油。
在局部找到一个最优的解。
却每加一次油可以看作是一个新的起点,用相同的递归方法进行下去。
最终将各个阶段的最优解合并为原问题的解得到原问题的求解。
最优子结构性质:当一个问题大的最优解包含着它的子问题的最优解时,称该问题具有最优子结构性质。
由于(b[1],b[2],……b[n])是这段路程加油次数最少的一个满足贪心选择性质的最优解,则易知若在第一个加油站加油时,b[1]=1,则(b[2],b[3],……b[n])是从a[2]到a[n]这段路程上加油次数最少且这段路程上的加油站个数为(a[2],a[3],……a[n])的最优解,即每次汽车中剩下的油不能在行驶到下一个加油站时我们才在这个加油站加一次油,每个过程从加油开始行驶到再次加油满足贪心且每一次加油后相当于与起点具有相同的条件,每个过程都是相同且独立,也就是说加油次数最少具有最优子结构性质。
贪心算法时间复杂度分析:由于若想知道该在哪个加油站加油就必须遍历所有的加油站,且不需要重复遍历,所以时间复杂度为O(n)。
核心算法:for(j=0;j<=k;j++){m+=l[j];if(m+l[j+1]>=7){A[j+1]=true;m=0;}}cout<<"在第";for(int s=0;s<=k;s++)if(A[s]==true){c++;cout<<s<<" ";}四、程序调试及运行结果分析调试结果:结果分析:该题设在加满油后可行驶的N千米这段路程上任取两个加油站A、B,且A距离始点比B距离始点近,则若在B加油不能到达终点那么在A加油一定不能到达终点。
因为m+N<n+N,即在B点加油可行驶的路程比在A点加油可行驶的路程要长n-m千米,所以只要终点不在B、C之间且在C的右边的话,根据贪心选择,为使加油次数最少就会选择距离加满油得点远一些的加油站去加油,因此,加油次数最少满足贪心选择性质五、实验总结#include<iostream>using namespace std;int main(){inti,j,n,k,l[10],c=0,m=0;bool A[10];cout<<"请输入加满油后可行驶的距离(km):";cin>>n;cout<<"请输入途中所经的加油站个数:";cin>>k;cout<<"请输入每相邻两个加油站之间的距离:"<<endl;for(i=0;i<=k;i++)cin>>l[i];for(i=0;i<=k;i++)A[i]=false;for(j=0;j<=k;j++){m+=l[j];if(m+l[j+1]>=7){A[j+1]=true;m=0;}}cout<<"在第";for(int s=0;s<=k;s++)if(A[s]==true){c++;cout<<s<<" ";}cout<<"个加油站加油了! "<<endl;cout<<"最少加油次数为:"<<c<<endl;system("pause");return 0;}六、实验总结在本次的实验中通过实践,自己又对贪心算法有了一个比较深得理解,虽然在编写代码的时候出现了错误,但在耐心排错最终也解决了问题。