算法设计第四章部分作业

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
void SiftHeap(int r[ ], int k, int n);//堆排序函数
int main()
{
int m;
int r[]={47,33,35,2,18,71,26,13};
int i,n=8;
HeapSort(r, n);//调用函数建立一个大根堆
for( i=0;i<8;i++)
cout<<r[i]<<" ";
cout<<endl;
cout<<"大根堆中要删除的元素的下标为:";
cin>>m;//输入大根堆中要删除的元素的下标
if(m<0||m>=n)
cout<<"要删除的元素的不存在"<<endl;
else
{
int temp;
temp=r[m];//将该元素的下标与大根堆最后一个元素交换,然后将前n-1个元素进行大根堆排序即可
算法:
输入:火柴的数量和第二个让人拿的火柴数量
输出:第一个拿的火柴数量
1.构造fun()函数,让A拿的火柴数是第二个人拿完后的数量模5的值
2.判断n%5的值
3.如果模值不等于0,调用fun()函数
4.进行递归调用fun知道火柴拿完为止
程序:
//火柴问题,如果火柴根数是5的倍数,那么只要B不是傻瓜A就输定了!反之如果不是5的倍数,那么A每次只要拿n%5的模值就一定能赢
i = j; j = 2 * i+1; //被筛结点位于原来结点j的位置
}
}
}
void HeapSort(int r[ ], int n)
{
int i;
for (i = (n-1)/2; i >= 0; i--) //初始建堆,从最后一个分支结点至根结点
SiftHeap(r, i, n) ;
}
第7题:
4.进行while循环做递归处理
5.返回最后的值
6.调用函数输出结果
程序:
//俄式乘法算法
#include<iostream>
using namespace std;
int fun(int a,int b)
{
int temp;
if(a>b)//大乘小除,减少运算步骤
{
temp=b;
b=a;
a=temp;
const int N = 12; //假设求解12枚硬币问题
int a[N] = {2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2};
int Coin(int low, int high, int n);
int main()
{
int i=Coin(0,11,12);
cout<<"假币是第"<<i<<"个"<<endl;
想法:
求两个数的乘积,根据已知提示可以采用俄式乘法,即是采用减治法将被乘数一直减小到1,同时将乘数以2倍的方式增大,同时将减去过程中产生的数累加最后一个求和
算法:
输入:两个正整数
输出:l两个数的乘积
1.构造一个俄式乘法函数fun()
2.输入两个数,对两个数比较大小,将较小的数作为被乘数
3.判断被乘数的奇偶性,若是偶数则减半,若是技术则减1再减半
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交换
算法第4-7章部分答案
第四章
第4题:
想法:
求两个正整数m和n的最小公倍数,由题目给出的提示可以知道,m和n的最小公倍数等于两个数的积除以它们的最大公约数。在第一张的事后要我们就已经用欧几里德算法求过两个数的最大公约数,所以对于题目4,我们就可以直接引用欧几里德算法辅助求最小公倍数。
算法:
输入:两个自然数m和n
b=b*2;
}
}
count=a*b+s;
return count;
}
int main()
{
int m,n;
int sum;
cout<<"请输入两个乘数:";
cin>>n>>m;
sum=fun(n,m);
cout<<"计算结果为:";
cout<<sum<<endl;
return 0;
}
第8题:
想法:
对于火柴游戏,如果起初所有火柴的数量是5的倍数,那么第一个人是不能赢的,如果要第一个人赢得游戏,那么,要在火柴数量不是5的倍数的情况下进行,不管第二个人拿几根火柴,只要第一个人拿的数量是n%5的模值即可赢得游戏!
{
int a, b, r,s;//r表示a,b两个数的最大公约数,s表示a,b的最大公倍数
cout<<"请输入两个自然数:";
cin>>a>>b;
r = CommFactor2(a, b);//调用函数求最大公约数
cout<<a<<"和"<<b<<"的最大公约数是:"<<r<<endl;
s=a*b/r;//最大公约数与最大公倍数之间的关系
算法:
输入:一个数组用来存放硬币的重量
输出:假币的位置
1.构造Coin()函数,将硬币分成三堆,如果硬币数量是3的倍数则均分成3组,如果不是则前两组分成n/3+1
2.累加比较重量来判断假币出现的地方
3.递归循环调用Coin()函数
4.返回假币的下标
5.在主函数中调用Coin()函数,输出结果
程序:
#include <iostream.h>
for (i = 0; i < num1; i++) //计算第1组硬币的重量和
add1 = add1 + a[low + i];
for (i = num1; i < num1 + num2; i++) //计算第2组硬币的重量和
add2 = add2 + a[low + i];
if (add1 < add2) //在第1组查找,下标范围是low~low+num1-1
算法:
1.输入:一个数组和左移位数
2.编写两个函数,一个是对称交换函数1,另一个是调用函数2,用函数2三次调用函数1,完成整个对称交换过程。
3.调用函数2
4.输出:左移后的数组
程序:
/*(升级版2)这个是用分治法将一个字符串(abcdefgh)左移3位(defghabc),具体用到的方法是对称交换和调用函数*/
cout<<"出错了!您只能拿1—4根火柴:"<<endl;
else
{
n=n-j;
return fun(n);//递归调用函数
}
}
}
}
int main()
{
cout<<"请输入火柴根数:";
int n;
cin>>n;
if(n%5==0)
cout<<"放弃吧!在B不是傻瓜的情况下A输定了!"<<endl;
cout<<a<<"和"<<b<<"的最大公倍数是:"<<s<<endl;
return 0;
}
int CommFactor2(int m, int n)//返回两个数的最大公约数
{
int r = m % n;
while (r != 0)
{
m = n;
n = r;
r = m % n;
}
return n;
return 0;
}//真币的重量是2,假币的重量是1
int Coin(int low, int high, int n) //在a[low]~a[high]中查找假币
{
int i, num1, num2, num3; // num1、num2和num3存储3组硬币的个数
int add1 = 0, add2 = 0; //add1和add2存储前两组硬币的重量和
#include<iostream>
using namespace std;
int fun(int n)
{
while(n>0)
{
int i,j;
i=n%5;
cout<<"A:"<<i<<endl;
n=n-i;
if(n>0)//当A拿完之后还有火柴时B才可以拿
{
cout<<"B:";
cin>>j;
if(j<1||j>4)
else //在第3组查找,下标范围low+num1+num2~high
Coin(low + num1 + num2, high, num3);
}
第五章
第6题:
想法:
对于第6题,用分治法进行求解的话,若是采用循环赋值的方式,如果字符的个数和左移的位数成倍数关系,那么算法就比较容易实现,但是如果不成比例关系,算法写起来就比较麻烦,所以,我用了另一种方式,进行三次对称交换就可以完成算法。
fun(a,k,n-1);//第二次调用函数1,将(defgh)对称交换得到(hgfed),最后a[]为(cbahgfed)
输出:m和n的最小公倍数
1.r=m%n;
1.循环直到r=0
1.1m=n;
1.2n=r;
1.3r=m%n;
2.returnn
3.调用2输出(m*n)/n
程序:
#include<iostream.h>
int CommFactor2(int m, int n);//求两个数的最大公约数
int main()
{
if(i<=(m+k)/2)
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
void xun(char a[],int k,int n)//(函数2)第二个调用函数,调用函数1
{
fun(a,0,k-1);//第一次调用函数1,将(abc)对称交换得到(cba),最后a[]为(cbadefgh)
#include<iostream>
usiБайду номын сангаасg namespace std;
void fun(char *a,int m,int k)//(函数1)对称交换函数(注意函数1和函数2书写的顺序,不要写反了,先有函数1,再写函数2)
{
int temp;
int i,j;
for(i=m,j=k;i<=k;i++,j--)
}
第6题:
想法:
首先要建立一个大根堆,然后实现删除操作,关键是如何实现删除操作,我的想法是将要删除的元素和建立的大根堆的最后一个元素交换,然后再调用建立大根堆的函数将前n-1个函数进行大根堆操作
算法:
输入:要删除的元素的下标
输出:删除后排序好的大根堆
1.构造一个大根堆堆顺序函数SiftHeap()
2.构造一个大根堆函数初始建堆函数HeapSort(),调用函数SiftHeap()
if (n == 1) //递归结束的条件
return low + 1; //返回的是序号,即下标加1
if (n % 3 == 0) //3组硬币的个数相同
num1 = num2 = n / 3;
else
num1 = num2 = n / 3 + 1; //前两组有n / 3 + 1枚硬币
num3 = n - num1 - num2;
r[m]=r[n-1];
r[n-1]=temp;
}
HeapSort(r, n-1);
for( i=0;i<7;i++)
cout<<r[i]<<" ";
return 0;
}
void SiftHeap(int r[ ], int k, int n)
{
int i, j, temp;
i = k; j = 2 * i +1; //置i为要筛的结点,j为i的左孩子
else fun(n);
return 0;
}
第10题:
想法:
这个想法是基于已知假币的轻重的情况下进行的,我假设假币比真币轻来进行试验,也可以假设假币比真币重,只需要稍微改写一下程序即可。首先,我将硬币分成3堆,用数组来存放硬币的重量,随便假设一个数组元素为假,用累加判断大小的方式来判断假币出现在哪一堆分组中,对可能出现的三种情况进行递归调用Coin()函数来进行循环判断,直到找到假币为止
3.建立初始大根堆
4.输入要删除的元素的下标
5.将要删除的元素与最后一个一个元素交换
6.建立前n-1个元素的大根堆
程序:
//想法:先将已知序列排列成一个大根堆,删除某个元素后,将最后一个元素赋值给删除节点,然后再进行堆排序(堆排序只是有序排序中的一部分)
#include <iostream.h>
void HeapSort(int r[ ], int n);//建立堆以及堆中元素整体排序
}
int count,s=0;//count用于存放结果,s用于存放计算过程中奇数a减1产生的累加值
while(a>1)
{
if(a%2==0)//若a为偶数
{
a=a/2;
b=b*2;
}
else if(a%2==1)//若a为奇数
{
a=(a-1)/2;
s+=b;//注意s和b的位置不可以交换哦,因为是b未加倍之前的累加和
return Coin(low, low + num1 - 1, num1);
else if (add1 > add2) //在第2组查找,下标范围low+num1~low+num1+num2-1
return Coin(low + num1, low + num1 + num2 - 1, num2);
相关文档
最新文档