1.
分治策略是算法设计的重要策略之一,该策略的基本思想是把问题进行分解成一些子问题,通过子问题的求解完成对原问题的求解。其关键是分解和合并,好的分解或合并方法才会产生高效的分治算法。
分治策略设计出的算法最常见的就是递归算法。但是如果在分解时,分解出的子问题有很多是重复的,那么这样的分治(递归)算法求解问题的效率就非常低。例如斐波那契数问题,如果采用递归求解,算法效率非常低:O( 2n )。而如果采用递推求解(动态规划自底向上求解),算法效率非常高:O(n)。
现在请你编写程序,统计计算一个斐波那契数时分解出的各子问题的个数。
斐波那契数的定义如下:
Fib(0)=0
Fib(1)=1
Fib(n)=Fib(n-1)+Fib(n-2)
输入: 一个整数n,即计算Fib(n)
输出:n+1行,即各个子问题的值及该子问题的个数。
例如
输入:
5
输出:
Fib(0)=0,spn=3
Fib(1)=1,spn=5
Fib(2)=1,spn=3
Fib(3)=2,spn=2
Fib(4)=3,spn=1
Fib(5)=5,spn=1
#include <iostream>
int fib[100005];
int spn[100005];
int n,i,j;
using namespace std;
int f(int n){
spn[n]++;
if(n==0){
return 0;
}
else if(n==1){
return 1;
}
return f(n-1)+f(n-2);
}
int main()
{
cin>>n;
fib[0]=0;
fib[1]=1;
for(i=0;i<=n;i++){
if(i==0){
continue;
}
else if(i==1){
continue;
}
else{
fib[i] = fib[i-1] + fib[i-2];
}
}
f(n);
for(i=0;i<=n;i++){
cout<<"Fib("<<i<<")="<<fib[i]<<",spn="<<spn[i]<<endl;
}
return 0;
}
2.
每个活动都有一个要求使用该资源的起止时间si,fi,且si<fi。如果选择了活动ai,则它在半开的时间区间[si,fi)内占有资源。两个活动ai,aj称为是相容的,当且仅当它们的时间区间[si,fi)和[sj,fj)不相交,即si>=fj 或 sj >=fi。现要求在所给定的活动集中选出最大的相容活动子集。(提示:贪心策略)
主函数已经给出, 请补充 Sort 和 Select 函数。 答案区只提交两个函数代码,不允许补充或修改其他代码!
#define Maxn 100
//定义活动的类型
typedef struct act_Node
{ int Id; //活动ID
int s_Time; //活动开始时间
int f_Time; //活动结束时间
} ACND;
// ******** Sort 函数 **********
// ******** Select 函数 **********
int main()
{ ACND arr[Maxn];
int an,i;
cin>>an; //读入活动个数
//读入各个活动的编号和占用资源的起止时间
for(i=0;i<an;i++)
cin>>arr[i].Id>>arr[i].s_Time>>arr[i].f_Time;
Sort(an,arr);
Select(an,arr);
return 0;
}
输入,有多行,第1行是活动的个数n,后面n行,每行3个整数,是每个活动的编号、占用资源的开始时间、结束时间
输出,选出的最大活动子集,即有多行,每行包括活动的编号、开始时间、结束时间。
例如:
输入:
11
1 3 8
2 2 13
3 1 4
4 5 7
5 6 10
6 8 11
7 12 14
8 5 9
9 3 5
10 0 6
11 8 12
输出:
3:1-4
4:5-7
6:8-11
7:12-14
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
//定义允许的最大活动数
#define Maxn 100
//定义活动的类型
typedef struct act_Node
{ int Id; //活动ID
int s_Time; //活动开始时间
int f_Time; //活动结束时间
} ACND;
//对活动按贪心准则排序
void Sort(int n,ACND arr[])
{
int temp1,temp2,temp3;
for(int i=0;i<n-1;i++)
{
for(int j=i;j<n;j++)
{
if(arr[i].f_Time>arr[j].f_Time)
{
temp1=arr[i].Id;
arr[i].Id=arr[j].Id;
arr[j].Id=temp1;
temp2=arr[i].s_Time;
arr[i].s_Time=arr[j].s_Time;
arr[j].s_Time=temp2;
temp3=arr[i].f_Time;
arr[i].f_Time=arr[j].f_Time;
arr[j].f_Time=temp3;
}
else if(arr[i].f_Time==arr[j].f_Time)
{
if(arr[i].Id>arr[j].Id)
{
temp1=arr[i].Id;
arr[i].Id=arr[j].Id;
arr[j].Id=temp1;
temp2=arr[i].s_Time;
arr[i].s_Time=arr[j].s_Time;
arr[j].s_Time=temp2;
temp3=arr[i].f_Time;
arr[i].f_Time=arr[j].f_Time;
arr[j].f_Time=temp3;
}
}
}
}
}
//进行贪心选择,得到最大相容的活动集合输出
void Select(int n,ACND arr[])
{
int now=0,count=0;
int amount[100],ans1[100],ans2[100];
amount[now]=arr[0].Id;
ans1[now]=arr[0].s_Time;
ans2[now]=arr[0].f_Time;
for(int j=1;j<n;j++)
{
if(arr[j].s_Time>=arr[now].f_Time)
{
now=j;
++count;
amount[count]=arr[j].Id;
ans1[count]=arr[j].s_Time;
ans2[count]=arr[j].f_Time;
}
}
for(int l=0;l<=count;l++)
{
cout<<amount[l]<<":"<<ans1[l]<<"-"<<ans2[l]<<endl;
}
}
int main()
{ ACND arr[Maxn];
int an,i;
cin>>an; //读入活动个数
//读入各个活动的编号和占用资源的起止时间
for(i=0;i<an;i++)
cin>>arr[i].Id>>arr[i].s_Time>>arr[i].f_Time;
//对活动按贪心准则进行排序
Sort(an,arr);
//进行贪心选择,获得最优解并输出
Select(an,arr);
return 0;
}
3.
假设栈ADT的数据元素为整数,栈ADT的实现采用顺序存储结构。现要用栈来辅助完成任意非负十进制整数到Base(Base不大于35)进制的转换。部分代码已经给出,请补充完善栈溢出处理函数和主函数。 注意:只提交需要补充的函数,其他代码不允许自己重写和修改。
栈溢出处理函数overflowProcess:当栈满时,将栈的空间在原来基础上扩大1倍。
主函数: 输入一个非负十进制整数n及要转换的进制Base,输出其转换后的进制形式,以及长度。输出格式如下:
($...$)10=(#...#)Base
Length=转换进制后数的位数
其中$...$是输入的十进制数n,#...#是转换得到的Base进制数,如果转换后位码多于1位,则用大写字母A,B,...等表示,10-A, 11-B,......
例如,输入:1024 2
输出:(1024)10=(10000000000)2
Length=11
再如,输入: 25 30
输出:(25)10=(P)30
Length=1
预置代码如下:
#include
using namespace std;
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
class SeqStack
{ //顺序栈类定义
private:
ElemType *elements; //数组存放栈元素
int top; //栈顶指示器
int maxSize; //栈最大容量
void overflowProcess(); //栈的溢出处理
public:
SeqStack(int sz); //构造函数
~SeqStack() { delete []elements; }; //析构函数
void Push(ElemType x); //进栈
int Pop(ElemType &x); //出栈
int IsEmpty() const { return top == -1; }
int IsFull() const { return top == maxSize-1; }
int GetSize() const {return top+1;}
};
SeqStack::SeqStack(int sz)
{ elements=new ElemType[sz]; //申请连续空间
if(elements==NULL) {cout<<"空间申请错误!"<<endl;exit(1);}
else { top=-1; //栈顶指示器指向栈底
maxSize=sz; //栈的最大空间
};
};
/*
补充overflowProcess() 函数
*/
void SeqStack::Push(ElemType x)
{ //若栈满,则溢出处理,将元素x插入该栈栈顶
if (IsFull() == 1) overflowProcess(); //栈满
elements[++top] = x; //栈顶指针先加1, 再元素进栈
};
int SeqStack::Pop(ElemType & x)
{//若栈不空,函数退出栈顶元素并将栈顶元素的值赋给x,
//返回true,否则返回false
if (IsEmpty() == 1) return 0;
x = elements[top--]; //先取元素,栈顶指针退1
return 1; //退栈成功
};
/*
补充mian()函数
*/
void SeqStack::overflowProcess(){
maxSize = maxSize*2+1;
}
int main(){
int n,base,x,reg;
int sum=0,ans=0;
SeqStack *result=new SeqStack(1005);
cin>>n>>base;
reg=n;
if(n==0){
result->Push(0);
}
while(n!=0){
result->Push(n%base);
n = n/base;
sum++;
}
ans = result->Pop(x);
cout<<'('<<reg<<')'<<10<<'='<<'(';
while(ans!=0){
if(base>=11){
if(x>=10){
cout<<(char)(x-10+65);
}
else cout<<x;
}
else cout<<x;
ans=result->Pop(x);
}
cout<<')'<<base<<endl;
cout<<"Length="<<sum<<endl;
return 0;
}
4.
假设线性表ADT的数据元素类型为正整数,采用带头结点的单链式存储结构。线性表ADT实现的大部分代码已经给出,请补充写出类的两个成员函数insert和reverse。 注意:只需提交需要补充的函数代码,其他代码不能自己重写和修改。
insert函数:在元素值从小到大有序的线性表中插入一个元素,仍然保持有序。
reverse函数:实现线性表元素的倒置,即将线性表中数据元素的顺序反转。
线性表元素输入时,以 endTag 作为结束标志。
例如输入: 3 8 7 2 4 9 1 6 5 0
则输出:9 8 7 6 5 4 3 2 1
预置代码如下: (其中/* */ 部分是要补充的insert和reverse函数)
#include
#include<stdlib.h>
using namespace std;
typedef int ElemType; //数据元素类型
class List; //前视定义,否则友元无法定义
//结点类定义
class LinkNode
{ friend class List;
private:
LinkNode *link;
ElemType data;
public:
LinkNode (LinkNode *ptr = NULL) {link=ptr;}
LinkNode(const ElemType & item, LinkNode *ptr = NULL){ data=item;link=ptr;}
~LinkNode(){};
};
//单链表类定义
class List
{ private:
LinkNode *first; //指向链表头结点的指针
public:
List (ElemType x) { first = new LinkNode (x);} // 带头结点
~List (){ MakeEmpty();} //析构函数
void MakeEmpty ( ); //线性表置空
void insert(ElemType val); //在有序线性表中插入元素val
void reverse(); //线性表的倒置
void output(); //线性表的输出
};
void List:: MakeEmpty ( )
{ LinkNode *q;
while ( first->link != NULL )
{ q = first->link; //指向别摘下结点
first->link = q->link;//从链中摘下结点
delete q; //释放摘下的结点
}
};
void List ::output ( )
{ LinkNode *p=first->link;
while(p!=NULL)
{ if(p==first->link) cout<data;
else cout<<" "<<p->data;
p=p->link;
}
cout<<endl;
}
/*
请写出 insert 成员函数
请写出 reverse 成员函数
*/
int main()
{ List list(0);
ElemType endTag=0;
ElemType val;
//下面通过不断读入元素,插入到有序单链表中,建立从小到大的有序单链表
cin>>val;
while(val!=endTag)
{ list.insert(val); //在有序表中插入一个元素
cin>>val;
}
list.reverse (); //线性表倒置
cout<<"The result is:"<<endl;
list.output ();
return 0;
}
void List::insert(ElemType val)
{
cont++;
arr[cont]=val;
}
void List::reverse()
{
for(int i=1;i<=cont-1;i++)
{
for(int j=1;j<=cont-1;j++)
{
if(arr[j]<arr[j+1])
{
int t=arr[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
}
for(int i=1;i<=cont;i++)
{
LinkNode *p;
p=first;
while(p->link!=NULL)
{
p=p->link;
}
LinkNode *t ;
t= new LinkNode (arr[i]);
p->link=t;
}
}
5.
假设二叉树的数据元素为字符,采用二叉链式存储结构。二叉树ADT实现的大部分代码已经给出,其中采用完全前序序列创建二叉树。请补充写出下列两个操作函数。 注意: 答案区只写出两个函数,其他代码不允许修改和重写、提交!
(1)计算以某结点为根的二叉树的高度;
(2)以前序顺序输出各个元素结点为根的子树的高度;
例如:有如右图的二叉树
输入:ABD@@E@@C@F@@
输出:
Height(A)=3
Height(B)=2
Height(D)=1
Height(E)=1
Height©=2
Height(F)=1
已给出的代码如下:
#include
#include <stdlib.h>
using namespace std;
//数据元素类型
typedef char ElemType;
//二叉树结点定义
typedef struct TreeNode
{ ElemType data;
struct TreeNode *lson, *rson;
} TreeNode;
//二叉树类
class BinaryTree
{ private:
TreeNode *root;
public:
BinaryTree() { root = NULL; };
~BinaryTree() { MakeEmpty(root); }
void MakeEmpty(TreeNode *t);
void create( ) { root = cp_create(root); }; //完全前序建立二叉树,空指针用@表示
TreeNode *cp_create(TreeNode *t);
//****** 要补充的函数height ********
int height(TreeNode *t) ; //求二叉树的高度
void output() { Pro_height(root); };
//****** 要补充的函数 Pro_height **********
void Pro_height(TreeNode *t); // 前序顺序输出各个元素结点为根的子树的高度
};
//二叉树置空
void BinaryTree::MakeEmpty(TreeNode *t)
{ if (t != NULL)
{ MakeEmpty(t->lson);
MakeEmpty(t->rson);
delete t;
}
}
//完全前序序列创建二叉树,空指针用@表示
TreeNode *BinaryTree::cp_create(TreeNode *t)
{ ElemType v;
cin >> v;
if (v != '@')
{ t = new TreeNode;
t->data = v;
t->lson = cp_create(t->lson);
t->rson = cp_create(t->rson);
}
else t = NULL;
return t;
}
//******************** 需要补充写出的两个函数 ****************************
//*******************************************************************************
//主函数
int main()
{ BinaryTree t;
t.create();
t.output();
return 0;
}
int BinaryTree::height(TreeNode* t)
{
if(t==NULL) return 0;
int lef=height(t->lson),rig=height(t->rson);
return max(lef,rig)+1;
}
void BinaryTree::Pro_height(TreeNode* t)
{
if(t==NULL) return;
cout<<"Height("<<t->data<<")="<<height(t)<<endl;
Pro_height(t->lson);
Pro_height(t->rson);
}
6.
假设二叉树的数据元素为字符,采用二叉链式存储结构。二叉树ADT实现的大部分代码已经给出,其中二叉树采用完全前序序列创建。请补充一个二叉树的输出函数,要求按目录缩进的形式输出一棵二叉树,同时要输出目录的层次。层次占2位、元素占1位,间隔4个位置(即共占7个位置)。 注意:答案区只写指定补充的函数代码,其他给定的代码不允许重写、修改和提交!
例如:有如右图的二叉树
输入:ABD@@E@@C@F@@
输出:
1A
2B
3D
3E
2C
3F
给出的代码如下:
#include
#include <stdlib.h>
#include<stdio.h>
using namespace std;
//数据元素类型
typedef char ElemType;
//二叉树结点定义
typedef struct TreeNode
{ ElemType data;
struct TreeNode *lson, *rson;
} TreeNode;
//二叉树类
class BinaryTree
{ private:
TreeNode *root;
public:
BinaryTree() { root = NULL; };
~BinaryTree() { MakeEmpty(root); }
void MakeEmpty(TreeNode *t);
void create( ) { root = cp_create(root); }; //完全前序建立二叉树,空指针用@表示
TreeNode *cp_create(TreeNode *t);
void output( ) { Index_print(root,1); };
//*********** 下面是需要自己完成的函数 ******************
void Index_print(TreeNode *t,int l); //缩进目录形式输出二叉树
};
//二叉树置空
void BinaryTree::MakeEmpty(TreeNode *t)
{ if (t != NULL)
{ MakeEmpty(t->lson);
MakeEmpty(t->rson);
delete t;
}
}
//完全前序序列创建二叉树,空指针用@表示
TreeNode *BinaryTree::cp_create(TreeNode *t)
{ ElemType v;
cin >> v;
if (v != '@')
{ t = new TreeNode;
t->data = v;
t->lson = cp_create(t->lson);
t->rson = cp_create(t->rson);
}
else t = NULL;
return t;
}
//*****下面是要补充的函数Index_print *************
//*************************************************
//主函数
int main()
{ BinaryTree t;
t.create(); //创建二叉树
t.output(); //按规定格式输出二叉树
cout<< endl;
return 0;
}
void BinaryTree::Index_print(TreeNode* t, int l)
{
if (t==NULL) return;
else {
for (int i = 0; i < l - 1; i++) {
cout << " ";
}
printf("%2d", l);
cout << t->data << endl;
Index_print(t->lson, l + 1);
Index_print(t->rson, l + 1);
}
}
7.
假设无向、非加权图的数据元素为字符,采用邻接表存储结构。图的创建、存储结构输出等大部分操作的实现代码操作已经给出,请分别补充写出操作插入边、删除边的实现函数代码。
有关说明:
(1)插入边, int Insert_Edge(g,vi,vj)
输入:图g,要插入边的两个顶点元素vi,vj;
输出:返回插入的状态(成功、错误:边顶点不存在、错误:边重复),根据不同的状态会输出:
Error:Vertex does not exist! 或
Error:Edge repetition! 或
Edge insertion succeeded!
注:为了统一,邻接点链入链表时,链入在前面(表头位置)
(2)删除边, int Delete_Edge(g,vi,vj)
输入:图g,要删除边的两个顶点元素vi,vj;
输出:返回删除的状态(成功、错误:边顶点不存在、错误:边不存在),根据不同的状态会输出:
Error:Vertex does not exist!
Error:Edge does not exist!
Edge deletion succeeded!
(3)主函数中操作的控制: 1—创建图 2—输出图的存储结构 3—插入边 4—删除边 0—退出
创建图时,需要输入顶点个数、各个顶点元素、各条边,具体见样例;
输出存储结构时,输出格式见样例;
插入或删除边时,需要输入边的两个顶点元素;
例如:
1 //创建图操作
5 //图顶点的个数
abcde //顶点元素
** //输入边,**表示边输入结束
2 //输出图结构操作
3 //插入边操作
ab //边顶点
3
bc
4 //删除边操作
de
2
0
输出如下:
Adjacency List is:
a:
b:
c:
d:
e:
Edge insertion succeeded!
Edge insertion succeeded!
Error:Edge does not exist!
Adjacency List is:
a:–>b
b:–>c–>a
c:–>b
d:
e:
给出的代码如下: (请注意要求补充的函数的注释说明)
#define _CRT_SECURE_NO_WARNINGS
#include
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define Max_VertexNum 50 //允许图的顶点个数的最大值
typedef char VertexType; //定义数据元素(顶点)类型为char
//********************************************************************************
//邻接表存储结构
struct EdgeNode //定义边存储结点
{ int adjvex; //邻接点的存储位置
EdgeNode *next; //指向下邻接点
};
struct VertexNode //定义顶点存储结点
{ VertexType vertex; //数据元素
struct EdgeNode *link; //第一个邻接点
};
typedef struct Graph //定义邻接表图结构
{ int VexNum; //图的顶点个数
VertexNode Nodetable[Max_VertexNum]; //一维数组-邻接表
} Graphlnk; //定义邻接表存储的图类型
//**********************************************************************************
// 基于邻接表存储的 无向、非加权图的各种操作的实现
//** 创建图
void create_graph(Graphlnk &g)
{ VertexType v1, v2;
int i, j;
struct EdgeNode *p, *q;
cin >> g.VexNum; //读入图的顶点个数
while (g.VexNum < 0)
cin >> g.VexNum;
for (i = 0; i < g.VexNum; i++)
{ cin >> g.Nodetable[i].vertex; //输入顶点元素
g.Nodetable[i].link = NULL; //邻接表初始化
}
cin >> v1 >> v2; //输入边的两个顶点
while (v1 != ‘’&&v2 != '’)
{ for (i = 0; i < g.VexNum; i++)
if (g.Nodetable[i].vertex == v1) break;
for (j = 0; j < g.VexNum; j++)
if (g.Nodetable[j].vertex == v2) break;
if (i >= g.VexNum || j >= g.VexNum) cin >> v1 >> v2; //边顶点不正确,重新读
else //链入邻接点
{ p = (struct EdgeNode *)malloc(sizeof(struct EdgeNode));
p->adjvex = j;
p->next = g.Nodetable[i].link;
g.Nodetable[i].link = p;
q = (struct EdgeNode *)malloc(sizeof(struct EdgeNode));
q->adjvex = i;
q->next = g.Nodetable[j].link;
g.Nodetable[j].link = q;
cin >> v1 >> v2;
}
}
}
void print_graph(Graphlnk g)
{ int i;
struct EdgeNode *p;
cout << “Adjacency List is:” << endl;
for (i = 0; i < g.VexNum; i++)
{ cout << g.Nodetable[i].vertex << “:”;
p = g.Nodetable[i].link;
while (p != NULL)
{ cout << “–>” << g.Nodetable[p->adjvex].vertex;
p = p->next;
}
cout << endl;
}
}
//**********************************************************************
补充 插入边、删除边的函数
//**********************************************************************
int main()
{ Graphlnk g;
int ic;
VertexType vi, vj;
int k;
while (1)
{ //请输入要执行的操作:";
cin >> ic;
while (ic < 0 || ic>4)
cin >> ic;
if (ic == 1) create_graph(g); //创建图
if (ic == 2) print_graph(g); //输出图结构
if (ic == 3) //插入边
{ cin >> vi >> vj;
k = Insert_Edge(g, vi, vj);
if (k == -1) cout << “Error:Vertex does not exist!” << endl;
if(k==0) cout << “Error:Edge repetition!” << endl;
if(k==1) cout << “Edge insertion succeeded!” << endl;
}
if (ic == 4) //删除边
{ cin >> vi >> vj;
k = Delete_Edge(g, vi, vj);
if (k == -1) cout << “Error:Vertex does not exist!.” << endl;
if (k == 0) cout << “Error:Edge does not exist!” << endl;
if (k == 1) cout << “Edge deletion succeeded!” << endl;
}
if (ic == 0) break;
}
return 0;
}
int Insert_Edge(Graphlnk &g,char vi,char vj)
{
int i,j;
for (i = 0; i < g.VexNum; i++)
if (g.Nodetable[i].vertex == vi)
break;
for (j = 0; j < g.VexNum; j++)
if (g.Nodetable[j].vertex == vj)
break;
struct EdgeNode *p=g.Nodetable[i].link;
struct EdgeNode *q=g.Nodetable[j].link;
if (i >= g.VexNum || j >= g.VexNum)
return -1;
else //链入邻接点
{
while(p)
{
if(p->adjvex==j)
return 0;
p=p->next;
}
p = new EdgeNode;
p->adjvex = j;
p->next = g.Nodetable[i].link;
g.Nodetable[i].link = p;
q = new EdgeNode;
q->adjvex = i;
q->next = g.Nodetable[j].link;
g.Nodetable[j].link = q;
return 1;
}
}
int Delete_Edge(Graphlnk &g,char a,char b)
{
int l=-1,r=-1;
for(int i=0; i<g.VexNum; ++i)
{
if(g.Nodetable[i].vertex==a)
{
l=i;
break;
}
}
for(int i=0; i<g.VexNum; ++i)
{
if(g.Nodetable[i].vertex==b)
{
r=i;
break;
}
}
if(l==-1 || r==-1)
return -1;
EdgeNode *p=g.Nodetable[l].link,*q=NULL,*s=p;
while(p!=NULL&&p->adjvex!=r)
{
q=p;
p=p->next;
}
if(p!=NULL)
{
if(p==s)
g.Nodetable[l].link=p->next;
else
q->next=p->next;
delete p;
}
else
return 0;
p=g.Nodetable[r].link;q=NULL,s=p;
while(p->adjvex!=l)
{
q=p;
p=p->next;
}
if(p==s)
g.Nodetable[r].link=p->next;
else
q->next=p->next;
delete p;
return 1;
}