算法报告
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
4.f(n,n)=1+f(n,n-1)正整数n的划分是由s=n的划分和s<=n-1的划分构成
5.f(n,m)=f(n,m-1)+f(n-m,m),n>m>1正整数n的最大加数s不大于m的划分,是由s=m的划分和s<=m-1的划分组成
解题思路:
枚举出所有可能的情况并给出相应的函数表达式,利用条件递归的调用这些函数。
if(size==1)return ; //递归边界
int t=title++; //L形骨牌号
int s=size/2; //分割棋盘
//覆盖左上角棋盘
if(dr<tr+s && dc<tc+s)
//特殊方格在此棋盘中
ChessBoard(tr,tc,dr,dc,s);
else
{
board[tr+s-1][tc+s-1]=t;
int middle=(left+right)/2;
if(x==a[middle])return middle;
if(x>a[middle])return BinarySearch(a,middle+1,right,x);
else return BinarySearch(a,left,middle-1,x);
2.nleft>k-1,则继续在左子集中找选择问题的答案
3.,mleft<k-1,则继续在右子集中找选择问提的答案,选择k-nleft-1小的数
解题思路:
首先选第一个数据作为分界数据,将比它小的数据存储在它的左边,比它大的数据存储在它的右边,这样左右子集就是原问题分界后的独立子问题,再用同样的方法,继续划分,直到每个子集只有一个数据就完成查找了
基本算法:
1.先定义前2项为1,1,;
2.利用fib(n)=fib(n-1)+fib(n-2)来递推
解题思路:
利用递推算法来实现每一项的值为fib(n)=fib(n-1)+fib(n-2);
代码实现:
#include <iostream>
using namespace std;
int fib[50];
using namespace std;
static int title=1;
int board[1025][1025];
void ChessBoard(int tr,int tc,int dr,int dc,int size);
void ChessBoard(int tr,int tc,int dr,int dc,int size){
代码实现:
#include <iostream>
using namespace std;
int a[100][100];
void Copy (int tox ,int toy,int fromx,int fromy,int r);
void Table(int k);
void Table(int k)
}
cout<<endl;
}
}
6.棋盘覆盖问题
题意:
特殊棋盘式当k=2时16个特殊棋盘中一个。在棋盘覆盖问题中,要求用4中不同形状的L形骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任意2个L形骨牌不得重叠覆盖
基本算法:
1,将棋盘分割成4个子棋盘
2.在左上角的子棋盘中,
2.1判断是否有特殊方格,若存在,则递归调用函数继续覆盖
for(int i=0;i<r;i++)
for(int j=0;j<r;j++)
a[tox+i][toy+j]=a[fromx+i][fromy+j];
}
int main(){
int i,j;
Table(3);
for(i=0;i<8;i++){
for(j=0;j<8;j++){
cout<<a[i][j]<<" ";
//特殊方格在此棋盘中
ChessBoard(tr+s,tc+s,dr,dc,s);
else
{
board[tr+s][tc+s]=t;
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
int main(){
int i,j;
ChessBoard(0,0,0,1,4);
for(i=0;i<4;i++){
首先选第一个数据作为分界数据将比它小的数据存储在它的左边比它大的数据存储在它的右边这样左右子集就是原问题分界后的独立子问题再用同样的方法继续划分直到每个子集只有一个数据就完成查找了代码实现
算法设计第三章
1.Fibonacii数列
题意:
斐波那契数列是意大利数学家列昂纳多最先研究的一种递归数列,它的每一项都等于前两项之和。次此数列的前几项为1,1,2,3,5等
ChessBoard(tr,tc,tr+s-1,tc+s-1,s);
}
//覆盖右上角棋盘
if(dr<tr+s && dc>=tc+s)
//特殊方格在此棋盘中
ChessBoard(tr,tc+s,dr,dc,s);
else
{
board[tr+s-1][tc+s]=t;
ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
2.集合的全排列问题
题意:
设R={r1,r2,...., }是要进行的n个元素,显然一共有n!种排列。令 =R-{ }。集合X中元素的全排列记为perm(X),则( )perm(X)
表示在全排列perm(X)的每一个排列前加上前缀 得到的排列
基本算法:
1.当n=1时,perm(R)=(r),其中r是集合R中唯一的元素;
}
//覆盖左下角棋盘
if(dr>=tr+s && dc<tc+s)
//特殊方格在此棋盘中
ChessBoard(tr+s,tc,dr,dc,s);
else
{
board[tr+s][tc+s-1]=t;
ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
}
//覆盖右下角棋盘
if(dr>=tr+s && dc>=tc+s)
代码实现:
#include<iostream>
using namespace std;
#define NUM 1001
int a[NUM];
//在a[left:right]中选择第k个小的元素
int select(int left,int right,int k)
{
//找到了第k个小的元素
if(left>=right)return a[left];
2.当n>1时,perm(R)由( )Perm( ),( )Perm( ),....,( )perm( )构成
解题思路:
设一个m表示数组长度,k为其中某一项,递归的产生元素k~m的全排列,作为前k-1个元素的后缀
代码实现:
#include<iostream>
using namespace std;
void perm(int list[],int k,int m);//声明函数
perm(list,k+1,m);
swap(list[k],list[j]);
}
}
int main(){
int list[]={1,2,3,4};
perm(list,0,3);
}
3.整数划分问题
题意:
所谓整数划分,是指把一个正整数n表示成一系列正整数之和,正整数n的这种表示成为正整数的划分。正整数的不同划分的个数称为正整数n的划分数,记做p(n).
int i=left;
int j=right+1;
//把最左边的元素作为分界数据
int pivot =a[left];
while(true){
//在左侧寻找>=pivot的数
do{
i=i+1;
}while(a[i]<pivot);
//在右侧寻找<=pivot的数
do{
j=j-1;
}while(a[i]>pivot);
代码实现:
#include<iostream>
using namespace std;
int BinarySearch(int a[],int left,int right, int x);
int BinarySearch(int a[],int left,int right, int x){
while(left<=right){
{
int i,r;
int n=1<<k;
for( i=0;i<n;i++)
a[0][i]=i+1;
for( r=1;r<n;r<<=1)
for(i=0;i<n;i+=2*r){
Copy(r,r+i,0,i,r);
Copy(r,i,0,r+i,r);
}
}
void Copy (int tox ,int toy,int fromx,int fromy,int r){
基本算法:
1.取数组的中间数作为分界数,将数组分为左右两半
2.若要查找的数在左半部分,则递归调用函数查询左半部分
3.若要查找的数在右半部分,则递归调用函数查询右半部分
解题思路:
取a[n/2]与x作比较。如果x=a[n/2],则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部分搜索x。反之则反
int fibo(int n);
int fibo(int n){
fib[0]=1;
fib[1]=1;
for(int i=2;i<=n;i++)
fib[i]=fib[i-1]+fib[i-2];
return fib[n];
}
int main(){
int a;
cin>>a;
cout<<fibo(a);
}
}
return -1;
}wk.baidu.com
int main(){
int a[]={1,2,3,4,5,6,7,8,9};
cout<<BinarySearch(a,0,8,5)+1;
}
5.循环赛日程表
题意:
设有n个运动员要参加网球循环赛,满足每个选手必须与其他n-1个选手各赛一次,每个选手每天只能参赛一次,循环赛在n-1天内结束
2.2若不存在,则用t号L形骨牌覆盖右下角
3.其他子棋盘类同上
解题思路:
由于原棋盘只有一个特殊方格,这样划分后,这4个子棋盘中只有一个含有特殊方格,其余3个子棋盘中没有特殊方格,可以用一个L形骨牌覆盖着3个子棋盘的汇合处,将它们转化成特殊棋盘,以便采用递归调用的方法
代码实现:
#include<iostream>
基本算法:
1.当k=n时,矩阵元素的输出宽度定义为n/2
2.循环的将方正4等分分割,即边长每次缩小1/2,直到2*2的方格
3.方正复制,反递归,实现n*n的方阵
结题思路:
按分治策略,我们可以将所有选手分为两半,则n个选手的比赛日程表可通过n/2个选手的比赛日程表来决定,递归地用这种一分为二的策略对选手进行划分,直到只剩下两个选手时,比赛日程表的制定就变得很简单
void perm(int list[],int k,int m)
{
//构成了一次全排列输出结果
if(k==m)
{
for(int i=0;i<m;i++)
cout<<list[i]<<" ";
cout<<endl;
}
else
for(int j=k;j<=m;j++)
{swap(list[k],list[j]);
if (i>=j)break;
swap(a[i],a[j]);
}
if(j-left+1==k)return pivot;
a[left]=a[j];
a[j]=pivot;
if(j-left+1<k)
return select(j+1,right,k-j+left-1);
else return select(left,j-1,k);
for(j=0;j<4;j++){
cout<<board[i][j]<<" ";
}
cout<<endl;
}
}
7.选择问题
题意:
对于给定数组中,要求从中找出第k小的元素
基本算法:
利用快速排序算法的思想,记一趟快速排序后,分解出左子集中元素的个数为nleft,
1.nleft=k-1,则分界数据就是选择的数据
基本算法:
我们记n得m划分的个数为f(n,m),该问题就转化为求n的所有划分个数。
1.f(1,m)=1,m>=1,当年时,不论m的值为多少(m>0),只有一种划分即1个1
2.f(n,1)=1,n>=1,当m=1时,不论n的值为多少(n>0),只有一种划分即n个1
3.f(n,m)=f(n,n),m>=n,最打加数s实际上不能超过n
代码实现:
#include<iostream>
using namespace std;
int split(int n,int m);
int split(int n,int m){
if(n==1||m==1)return 1;
else if(n<m)return split(n,n);
else if(n==m) return split(n,n-1)+1;
else return split(n,m-1)+split(n-m,m);
}
int main(){
int a,b;
int sum=0;
cin>>a>>b;
cout<<split(a,b);
}
4.二分搜索算法
题意:
将n个元素分成个数大致相同的两半,取a[n/2]与x作比较。如果x=a[n/2],则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部分搜索x。反之则反
5.f(n,m)=f(n,m-1)+f(n-m,m),n>m>1正整数n的最大加数s不大于m的划分,是由s=m的划分和s<=m-1的划分组成
解题思路:
枚举出所有可能的情况并给出相应的函数表达式,利用条件递归的调用这些函数。
if(size==1)return ; //递归边界
int t=title++; //L形骨牌号
int s=size/2; //分割棋盘
//覆盖左上角棋盘
if(dr<tr+s && dc<tc+s)
//特殊方格在此棋盘中
ChessBoard(tr,tc,dr,dc,s);
else
{
board[tr+s-1][tc+s-1]=t;
int middle=(left+right)/2;
if(x==a[middle])return middle;
if(x>a[middle])return BinarySearch(a,middle+1,right,x);
else return BinarySearch(a,left,middle-1,x);
2.nleft>k-1,则继续在左子集中找选择问题的答案
3.,mleft<k-1,则继续在右子集中找选择问提的答案,选择k-nleft-1小的数
解题思路:
首先选第一个数据作为分界数据,将比它小的数据存储在它的左边,比它大的数据存储在它的右边,这样左右子集就是原问题分界后的独立子问题,再用同样的方法,继续划分,直到每个子集只有一个数据就完成查找了
基本算法:
1.先定义前2项为1,1,;
2.利用fib(n)=fib(n-1)+fib(n-2)来递推
解题思路:
利用递推算法来实现每一项的值为fib(n)=fib(n-1)+fib(n-2);
代码实现:
#include <iostream>
using namespace std;
int fib[50];
using namespace std;
static int title=1;
int board[1025][1025];
void ChessBoard(int tr,int tc,int dr,int dc,int size);
void ChessBoard(int tr,int tc,int dr,int dc,int size){
代码实现:
#include <iostream>
using namespace std;
int a[100][100];
void Copy (int tox ,int toy,int fromx,int fromy,int r);
void Table(int k);
void Table(int k)
}
cout<<endl;
}
}
6.棋盘覆盖问题
题意:
特殊棋盘式当k=2时16个特殊棋盘中一个。在棋盘覆盖问题中,要求用4中不同形状的L形骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且任意2个L形骨牌不得重叠覆盖
基本算法:
1,将棋盘分割成4个子棋盘
2.在左上角的子棋盘中,
2.1判断是否有特殊方格,若存在,则递归调用函数继续覆盖
for(int i=0;i<r;i++)
for(int j=0;j<r;j++)
a[tox+i][toy+j]=a[fromx+i][fromy+j];
}
int main(){
int i,j;
Table(3);
for(i=0;i<8;i++){
for(j=0;j<8;j++){
cout<<a[i][j]<<" ";
//特殊方格在此棋盘中
ChessBoard(tr+s,tc+s,dr,dc,s);
else
{
board[tr+s][tc+s]=t;
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
int main(){
int i,j;
ChessBoard(0,0,0,1,4);
for(i=0;i<4;i++){
首先选第一个数据作为分界数据将比它小的数据存储在它的左边比它大的数据存储在它的右边这样左右子集就是原问题分界后的独立子问题再用同样的方法继续划分直到每个子集只有一个数据就完成查找了代码实现
算法设计第三章
1.Fibonacii数列
题意:
斐波那契数列是意大利数学家列昂纳多最先研究的一种递归数列,它的每一项都等于前两项之和。次此数列的前几项为1,1,2,3,5等
ChessBoard(tr,tc,tr+s-1,tc+s-1,s);
}
//覆盖右上角棋盘
if(dr<tr+s && dc>=tc+s)
//特殊方格在此棋盘中
ChessBoard(tr,tc+s,dr,dc,s);
else
{
board[tr+s-1][tc+s]=t;
ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
2.集合的全排列问题
题意:
设R={r1,r2,...., }是要进行的n个元素,显然一共有n!种排列。令 =R-{ }。集合X中元素的全排列记为perm(X),则( )perm(X)
表示在全排列perm(X)的每一个排列前加上前缀 得到的排列
基本算法:
1.当n=1时,perm(R)=(r),其中r是集合R中唯一的元素;
}
//覆盖左下角棋盘
if(dr>=tr+s && dc<tc+s)
//特殊方格在此棋盘中
ChessBoard(tr+s,tc,dr,dc,s);
else
{
board[tr+s][tc+s-1]=t;
ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
}
//覆盖右下角棋盘
if(dr>=tr+s && dc>=tc+s)
代码实现:
#include<iostream>
using namespace std;
#define NUM 1001
int a[NUM];
//在a[left:right]中选择第k个小的元素
int select(int left,int right,int k)
{
//找到了第k个小的元素
if(left>=right)return a[left];
2.当n>1时,perm(R)由( )Perm( ),( )Perm( ),....,( )perm( )构成
解题思路:
设一个m表示数组长度,k为其中某一项,递归的产生元素k~m的全排列,作为前k-1个元素的后缀
代码实现:
#include<iostream>
using namespace std;
void perm(int list[],int k,int m);//声明函数
perm(list,k+1,m);
swap(list[k],list[j]);
}
}
int main(){
int list[]={1,2,3,4};
perm(list,0,3);
}
3.整数划分问题
题意:
所谓整数划分,是指把一个正整数n表示成一系列正整数之和,正整数n的这种表示成为正整数的划分。正整数的不同划分的个数称为正整数n的划分数,记做p(n).
int i=left;
int j=right+1;
//把最左边的元素作为分界数据
int pivot =a[left];
while(true){
//在左侧寻找>=pivot的数
do{
i=i+1;
}while(a[i]<pivot);
//在右侧寻找<=pivot的数
do{
j=j-1;
}while(a[i]>pivot);
代码实现:
#include<iostream>
using namespace std;
int BinarySearch(int a[],int left,int right, int x);
int BinarySearch(int a[],int left,int right, int x){
while(left<=right){
{
int i,r;
int n=1<<k;
for( i=0;i<n;i++)
a[0][i]=i+1;
for( r=1;r<n;r<<=1)
for(i=0;i<n;i+=2*r){
Copy(r,r+i,0,i,r);
Copy(r,i,0,r+i,r);
}
}
void Copy (int tox ,int toy,int fromx,int fromy,int r){
基本算法:
1.取数组的中间数作为分界数,将数组分为左右两半
2.若要查找的数在左半部分,则递归调用函数查询左半部分
3.若要查找的数在右半部分,则递归调用函数查询右半部分
解题思路:
取a[n/2]与x作比较。如果x=a[n/2],则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部分搜索x。反之则反
int fibo(int n);
int fibo(int n){
fib[0]=1;
fib[1]=1;
for(int i=2;i<=n;i++)
fib[i]=fib[i-1]+fib[i-2];
return fib[n];
}
int main(){
int a;
cin>>a;
cout<<fibo(a);
}
}
return -1;
}wk.baidu.com
int main(){
int a[]={1,2,3,4,5,6,7,8,9};
cout<<BinarySearch(a,0,8,5)+1;
}
5.循环赛日程表
题意:
设有n个运动员要参加网球循环赛,满足每个选手必须与其他n-1个选手各赛一次,每个选手每天只能参赛一次,循环赛在n-1天内结束
2.2若不存在,则用t号L形骨牌覆盖右下角
3.其他子棋盘类同上
解题思路:
由于原棋盘只有一个特殊方格,这样划分后,这4个子棋盘中只有一个含有特殊方格,其余3个子棋盘中没有特殊方格,可以用一个L形骨牌覆盖着3个子棋盘的汇合处,将它们转化成特殊棋盘,以便采用递归调用的方法
代码实现:
#include<iostream>
基本算法:
1.当k=n时,矩阵元素的输出宽度定义为n/2
2.循环的将方正4等分分割,即边长每次缩小1/2,直到2*2的方格
3.方正复制,反递归,实现n*n的方阵
结题思路:
按分治策略,我们可以将所有选手分为两半,则n个选手的比赛日程表可通过n/2个选手的比赛日程表来决定,递归地用这种一分为二的策略对选手进行划分,直到只剩下两个选手时,比赛日程表的制定就变得很简单
void perm(int list[],int k,int m)
{
//构成了一次全排列输出结果
if(k==m)
{
for(int i=0;i<m;i++)
cout<<list[i]<<" ";
cout<<endl;
}
else
for(int j=k;j<=m;j++)
{swap(list[k],list[j]);
if (i>=j)break;
swap(a[i],a[j]);
}
if(j-left+1==k)return pivot;
a[left]=a[j];
a[j]=pivot;
if(j-left+1<k)
return select(j+1,right,k-j+left-1);
else return select(left,j-1,k);
for(j=0;j<4;j++){
cout<<board[i][j]<<" ";
}
cout<<endl;
}
}
7.选择问题
题意:
对于给定数组中,要求从中找出第k小的元素
基本算法:
利用快速排序算法的思想,记一趟快速排序后,分解出左子集中元素的个数为nleft,
1.nleft=k-1,则分界数据就是选择的数据
基本算法:
我们记n得m划分的个数为f(n,m),该问题就转化为求n的所有划分个数。
1.f(1,m)=1,m>=1,当年时,不论m的值为多少(m>0),只有一种划分即1个1
2.f(n,1)=1,n>=1,当m=1时,不论n的值为多少(n>0),只有一种划分即n个1
3.f(n,m)=f(n,n),m>=n,最打加数s实际上不能超过n
代码实现:
#include<iostream>
using namespace std;
int split(int n,int m);
int split(int n,int m){
if(n==1||m==1)return 1;
else if(n<m)return split(n,n);
else if(n==m) return split(n,n-1)+1;
else return split(n,m-1)+split(n-m,m);
}
int main(){
int a,b;
int sum=0;
cin>>a>>b;
cout<<split(a,b);
}
4.二分搜索算法
题意:
将n个元素分成个数大致相同的两半,取a[n/2]与x作比较。如果x=a[n/2],则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部分搜索x。反之则反