4. 求两个正整数m和n的最小公倍数。(提示:m和n的最小公倍数lcm(m, n)与m和n的最大公约数gcd(m, n)之间有如下关系:lcm(m, n)=m×n/gcd(m, n))
//求两个数的最小公倍数
#include using namespace std;
int main (void) {
int a,b; int i=1;
cin>>a>>b;
while((i%a!=0)||(i%b!=0)) ++i;
cout<<\最小公倍数为:\
return 0; }
(该算法比较直接,要使其改进,可用欧几里得算法求得两个数的最大公约数,然后套用上面的公式再求最小公倍数)
5. 插入法调整堆。已知(k1, k2, ?, kn)是堆,设计算法将(k1, k2, ?, kn, kn+1)调整为堆(假设调整为大根堆)。
参照:
void SiftHeap(int r[ ], int k, int n) {
int i, j, temp;
i = k; j = 2 * i + 1; //置i为要筛的结点,j为i的左孩子 while (j < n) //筛选还没有进行到叶子 {
}
if (j < n-1 && r[j] < r[j+1]) j++; //比较i的左右孩子,j为较大者
if (r[i] > r[j]) //根结点已经大于左右孩子中的较大者 break; else {
temp = r[i]; r[i] = r[j]; r[j] = temp; //将被筛结点与结点j交换
i = j; j = 2 * i + 1; //被筛结点位于原来结点j的位置 }
}
进行调堆!
6. 设计算法实现在大根堆中删除一个元素,要求算法的时间复杂性为O(log2n)。
//将要删除的a[k]与最后一个元素a[n-1]交换 //然后进行调堆
void de_SiftHeap(int r[ ], int k, int n) {
int i, j, temp,temp1; i = k; j = 2 * i + 1; if(i<0||i>n-1) return error; else if(i==n-1) free(a[i]);
else //置i为要筛的结点,j为i的左孩子
while (j < n) //筛选还没有进行到叶子 {
temp1=a[i]; //将a[n-1]与a[k]交换; a[i]=a[n-1]; a[n-1]= temp1;
if (j < n-1 && r[j] < r[j+1]) j++; //比较i的左右孩子,j为较大者 if (r[i] > r[j]) //根结点已经大于左右孩子中的较大者 break; else { temp = r[i]; r[i] = r[j]; r[j] = temp; //将被筛结点与结点j交换 i = j; j = 2 * i + 1; //被筛结点位于原来结点j的位置 } } }
7. 计算两个正整数n和m的乘积有一个很有名的算法
n m 称为俄式乘法,其思想是利用了一个规模是n的解和一个50 65 25 130 130 规模是n/2的解之间的关系:n×m=n/2×2m(当n是偶
12 260 数)或:n×m=(n-1)/2×2m+m(当n是奇数),并以16 520 3 1040 1040 1 2080 + 2080 3250 图5.15 俄式乘法
×m=m作为算法结束的条件。例如,图5.15给出了利用俄式乘法计算50×65的例子。据说十九世纪的俄国农夫使用该算法并因此得名,这个算法也使得乘法的硬件实现速度非常快,因为只使用移位就可以完成二进制数的折半和加倍。请设计算法实现俄式乘法。
//俄式乘法
#include using namespace std;
int fun(int m,int n) {
int sum=0; int temp=n; while(m!=1) {
if(m%2==0)//如果n是偶数 {
n=n*2;
m=m/2; }
else//如果n是奇数 {
n=n*2;
sum+=temp; m=(m-1)/2; }
temp=n;//记录倒数第二个n的值 }
return sum+n; }
int main() {
int a,b;
while(cin>>a>>b) {
cout<8. 拿子游戏。考虑下面这个游戏:桌子上有一堆火柴,游戏开始时共有n根火柴,两个玩家轮流拿走1,2,3或4根火柴,拿走最后一根火柴的玩家为获胜方。请为先走的玩家设计一个制胜的策略(如果该策略存在)。