1、对下图所示的连通网络G,用克鲁斯卡尔(Kruskal)算法求G的最小生成树T,请写出在算法执行过程中,依次加入T的边集TE中的边。说明该算法的贪心策略和算法的基本思想,并简要分析算法的时间复杂度。
答:
解集:TE={(3,4), (2,3),(1,5),(4,6)(4,5)}
贪心策略:每次都在连接两个不同连通分量的边中选权值最小的边。
基本思想:首先将图中所有顶点都放到生成树中,然后每次都在连接两个不同连通分量的边中选权值最小的边,将其放入生成树中,直到生成树中有n-1条边。
时间复杂度为:O(eloge)
2、一个旅行者要驾车从 A 地到 B 地,A、B 两地间距离为 s。A、B 两地之间有n 个 加 油 站 , 已 知 第 i 个 加 油 站 离 起 点 A 的 距 离 为 di 公 里 , 0= d1< d2 < ….< dn < s,车加满油后可行驶 m 公里,出发之前汽车油箱为空。 应如何加油使得从 A 地到 B 地沿途加油次数最少?给出用贪心法求解该最优 化问题的贪心选择策略,写出求该最优化问题的最优值和最优解的贪心算法, 并分析算法的时间复杂性。
贪心选择策略:起点的加油站起每次加满油后不加油行驶尽可能远,油箱中的油耗尽前所能到达的最远的油站为止,在该油站再加满油。算法 MINSTOPS输入:A、B 两地间的距离 s,A、B 两地间的加油站数 n,车加满油后可行驶的公里数 m,存储各加油站离起点 A 的距离的数组 d[1..n]。输出:从 A 地到 B 地的最少加油次数 k 以及最优解 x[1..k](x[i]表示第 i 次加油的加油序号),若问题无解,则输出 no solutiond[n+1]=s; //设置虚拟加油站第 n+1 站。for i=1 to nif d[i+1]-d[i]>m thenoutput “no solution”;return //无解,返回end ifend fork=1; x[k]=1 //在第 1 站加满油。s1=m //s1 为用汽车的当前油量可行驶至的地点与 A 点的距离i=2while s1<sif d[i+1]>s1 then //以汽车的当前油量无法到达第 i+1 站。k=k+1;x[k]=i //在第 i 站加满油。s1=d[i]+m //刷新 s1 的值end ifi=i+1end whileoutput k, x[1..k]MINSTOPS最坏情况下的时间复杂性:Θ(n)
3、写出用背包问题贪心算法解决下列实例的过程。
P=(18,12,4,1)
W=(12,10,8,3)
M=25
实例符合 P(i)/W(i)≥P(i+1)/W(i+1)的顺序。CU←25,X←0W[1]< CU: x[1]←1; CU←CU-W[1]=13;W[2]< CU: x[2]←1; CU←CU-W[2]=3;W[3]>CU: x[3]←CU/ W[3]=3/8;实例的解为:(1,1,3/8,0)
4、设有 n 种面值为:
d1≥d2≥……≥dn的钱币,需要找零钱 M,如何选择钱币 dk,的数目 Xk,满足 d1×Xi+……dn×Xn=M ,使得 Xi+……Xn 最小
请选择贪心策略,并设计贪心算法。
贪心原则:每次选择最大面值硬币。CU←M;i←1;X←0; // X 为解向量While CU≠0 doX[i]←CU div d[i] // X[i]为第 i 中硬币数CU←CU-d[i]*X[i]i←i+1;repeat
5、有 n 个物品,已知 n=7, 利润为 P=(10,5,15,7,6,18,3),重量 W=(2,3,5,7,1,4,1), 背包容积 M=15,物品只能选择全部装入背包或不装入背包,设计贪心算法,并讨论是否可获 最优解。
1、定义结构体数组 G,将物品编号、利润、重量作为一个结构体:例如 G[k]={1,10,2} 求最优解,按利润/重量的递减序,有{5,6,1,6} {1,10,2,5}{6,18,4,9/2} {3,15,5,3} {7,3,1,3}{2,5,3,5/3} {4,7,7,1}算法procedure KNAPSACK(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)是解向量//real P(1:n),W(1:n),X(1:n),M,cu;integer i,n;X←0 //将解向量初始化为零//cu←M //cu 是背包剩余容量//for i←1 to n doif W(i)>cu thenexitendifX(i) ←1cu←cu-W(i)repeatend GREEDY-KNAPSACK根据算法得出的解:X= (1,1,1,1,1,0,0)获利润 52, 而解(1,1,1,1, 0, 1,0)可获利润 54因此贪心法不一定获得最优解。
6、试用贪心算法求解下列问题:将正整数 n 分解为若干个互不相同的自然数之和,使这些自然数的乘积最大。(15 分)
#include<iostream>#include<cstdio>using namespace std;//把自然数N分解成若干个互不相同的正整数,使乘积最大;/**题意挺晦涩的,就是说要维持这个会议召开需要满足几个条件,而要会议召开最久需要这个条件尽可能久的维持接着就需要了将整数N分解任意个不同的整数,使这些整数的乘积最大将N分解为N=a1+a2+a3+..+ak可以归纳出这么一些规律1.a1>1 如果a1=1,那么将a1加到ak上,必然使得到的这个乘积大于原来的乘积2.2>=a[i+1]-a[i]>=1,因为如果出现>2,可以将a[i+1],a[i]改为a[i+1]-1,a[i]+1,使得到的乘积更大3.最多只有一个i,使得a[i+1]-a[i]=2反证法,假设i<j,并且a[i+1]-a[i]=2,a[j+1]-a[j]=2,那么将a[i],a[j+1]替换成a[i]+1,a[j+1]-1将使得乘积更大4.a1<=3 如果a1>=4,那么将a1,a2替换成2,a1-1,a2-1将使得乘积更大5.如果a1=3,并且存在一个i使得a[i+1]-a[i]=2,那么i一定为t-1做法就是求出以2起始的最大连续自然数序列之和sum,使得sum的值不超过输入数n,然后分情况讨论:设此最大序列为2、3、……、w,则:1。若剩余值(n-sum)等于w,则最后输出序列为:3、4、……、w、w+2,即将原最大序列每项加1,再将最后剩余的一个1加到最后一项上。2。若剩余值(n-sum)小于w,则从序列的最大项i开始,从大到小依次将每项加1,直到剩余值用完。*/void dicomp(int n,int a[]){k=1;if(n<3){a[1]=0;return;};if(n<5){a[k]=1;a[++k]=n-1;return;}; …………………………(5 分)a[1]=2;n-=2;while(n>a[k]){k++;a[k]=a[k-1]+1;n-=a[k];};……………………………(10 分)if(n= =a[k]){a[k]++;n--;};for(int i=0;i<n;i++)a[k-i]++;}……………………………(15 分)
7、分别用贪心算法、动态规划法、回溯法设计 0-1 背包问题。要求:说明所使用的算法策略;写出算法实现的主要步骤;分析算法的时间。
答:
时间复杂度:O(nlogn)
分析:
首先计算每种物品单位重量的价值 Vi/Wi,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。
若将这种物品全部装入背包后,背包内的物品总重量未超过 C,则选择单位重量价值次高的物品并尽可能多地装入背包。
依此策 略一直地进行下去,直到背包装满为止。
算法:
void Knapsack(int n,float M,float v[],float w[],float x[])
{
Sort(n,v,w); //按单价降序排列
int i;
for (i=1;i<=n;i++)
x[i]=0;
float c=M;
for (i=1;i<=n;i++)
{
if (w[i]>c) break;
x[i]=1;
c-=w[i];
}
if (i<=n)
x[i]=c/w[i];
}
(2)动态规划法 O(nc)
m(i,j)是背包容量为 j,可选择物品为 i,i+1,…,n 时 0-1 背包问题的最优值。由 0-1背包问题的最优子结构性质,可以建立计算 m(i,j)的递归式如下。
void KnapSack(int v[],int w[],int c,int n,int m[][11])
{
int jMax=min(w[n]-1,c);
for (j=0;j<=jMax;j++)
/*m(n,j)=0
0=<j<w[n]*/
m[n][j]=0;
for (j=w[n];j<=c;j++)
/*m(n,j)=v[n]
j>=w[n]*/
m[n][j]=v[n];
for (i=n-1;i>1;i--)
{
int jMax=min(w[i]-1,c);
for (j=0;j<=jMax;j++)
/*m(i,j)=m(i+1,j)
0=<j<w[i]*/
m[i][j]=m[i+1][j];
for (j=w[i];j<=c;j++)/*m(n,j)=v[n]
j>=w[n]*/
m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
}
m[1][c]=m[2][c];
if(c>=w[1])
m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);
}
时间复杂度: O(2n)
cw:当前重量
cp:当前价值
bestp:当前最优值
void backtrack(int i)
//回溯法 i 初值 1
{
if(i > n) //到达叶结点
{
bestp = cp;
return;
}
if(cw + w[i] <= c) //搜索左子树
{
cw += w[i];
cp += p[i];
backtrack(i+1);
cw -= w[i];
cp -= p[i];
}
if(Bound(i+1)>bestp) //搜索右子树
backtrack(i+1);
}
8、通过键盘输入一个高精度的正整数 n(n 的有效位数≤240),去掉其中任意 s 个数字后,
剩下的数字按原左右次序将组成一个新的正整数。编程对给定的 n 和 s,寻找一种方案,使
得剩下的数字组成的新数最小。
【样例输入】
178543
S=4
【样例输出】
13
为了尽可能地逼近目标,我们选取的贪心策略为:
每一步总是选择一个使剩下的数最小的数字删去,即按高位到低位的顺序搜索,
若各位数字递增,则删除最后一个数字,否则删除第一个递减区间的首字符。
然后回到串首,按上述规则再删除下一个数字。重复以上过程 s 次,剩下的数字串便是问题的解了。
算法:
输入s, n;
while(s > 0 )
{
i=1; //从串首开始找
while (i < length(n)) && (n[i]<n[i+1])
{
i++;
}
delete(n,i,1); //删除字符串n的第i个字符
s--;
}
while (length(n)>1)&& (n[1]='0')
delete(n,1,1); //删去串首可能产生的无用零
输出n;
9、 机器调度问题。
问题描述:现在有 n 件任务和无限多台的机器,任务可以在机器上得到 处理。每件任务的开始时间为 si,完成时间为 fi,si
解:
