文章目录
- 1、棋盘覆盖问题
- 2、合并排序问题
- 3、集合最大元问题
- 4、循环赛日程表
一、实验目的:
掌握分治算法的基本思想,掌握分治算法的设计步骤及用递归技术实现分治策略。
二、实验所用仪器及环境
Windows 7 以上操作系统,PC机,codeblocks环境
三、 实验原理:
算法总体思想:对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解。
分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之,如下图所示。
四、 实验内容:
1、棋盘覆盖问题
在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000
int chess[maxn][maxn]={0};
int gupaihao=1;///公共变量骨牌号
void chesser(int zuoshangY,int zuoshangX,int teshuY,int teshuX,int n)///n是实际大小,
{
if(n==1)//bianjie
{
return ;
}
int t=gupaihao++;
int dangqiankuaidaxiao=n/2;///2K,不怕出0.5
//左上
if(zuoshangY+dangqiankuaidaxiao>teshuY&&zuoshangX+dangqiankuaidaxiao>teshuX)
///有特殊方格
{
///接着分
chesser(zuoshangY,zuoshangX,teshuY,teshuX,dangqiankuaidaxiao);
}
else{//yao else
///meiyou,左上角棋盘要盖右下角
chess[zuoshangY+dangqiankuaidaxiao-1][zuoshangX+dangqiankuaidaxiao-1]=t;
///剩下的这不就有了吗
chesser(zuoshangY,zuoshangX,zuoshangY+dangqiankuaidaxiao-1,zuoshangX+dangqiankuaidaxiao-1,dangqiankuaidaxiao);///右下角成为新的特殊点
}
///然后是剩下三个,一样思路
//右上
if(zuoshangY+dangqiankuaidaxiao>teshuY&&zuoshangX+dangqiankuaidaxiao<=teshuX)
{
chesser(zuoshangY,zuoshangX+dangqiankuaidaxiao,teshuY,teshuX,dangqiankuaidaxiao);
}
else{
///把左下角改喽
chess[zuoshangY+dangqiankuaidaxiao-1][zuoshangX+dangqiankuaidaxiao]=t;
chesser(zuoshangY,zuoshangX+dangqiankuaidaxiao,zuoshangY+dangqiankuaidaxiao-1,zuoshangX+dangqiankuaidaxiao-1,dangqiankuaidaxiao);
}
//zuoxia
if(zuoshangY+dangqiankuaidaxiao<=teshuY&&teshuX<zuoshangX+dangqiankuaidaxiao)
{
chesser(zuoshangY+dangqiankuaidaxiao,zuoshangX,teshuY,teshuX,dangqiankuaidaxiao);
}
else{
chess[zuoshangY+dangqiankuaidaxiao][zuoshangX+dangqiankuaidaxiao-1]=t;
chesser(zuoshangY+dangqiankuaidaxiao,zuoshangX,zuoshangY+dangqiankuaidaxiao,zuoshangX+dangqiankuaidaxiao-1,dangqiankuaidaxiao);
}
//youxia
if(zuoshangY+dangqiankuaidaxiao<=teshuY&&zuoshangX+dangqiankuaidaxiao<=teshuX)
{
chesser(zuoshangY+dangqiankuaidaxiao,zuoshangX+dangqiankuaidaxiao,teshuY,teshuX,dangqiankuaidaxiao);
}
else{
chess[zuoshangY+dangqiankuaidaxiao][zuoshangX+dangqiankuaidaxiao]=t;
chesser(zuoshangY+dangqiankuaidaxiao,zuoshangX+dangqiankuaidaxiao,zuoshangY+dangqiankuaidaxiao,zuoshangX+dangqiankuaidaxiao,dangqiankuaidaxiao);
}
}
int main()
{
int n;//棋盘大小
cin>>n;
//input 0 无 -1有
int X,Y;
///横X,纵Y
cin>>X>>Y;
chess[X][Y]=-1;
chesser(0,0,Y,X,n);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%3d ",chess[i][j]);
//cout<<chess[i][j]<<" ";
}
cout<<"\n";
}
return 0;
}
///input
//8
//6 2
2、合并排序问题
对n个元素组成的序列进行排序。
基本思想:将待排序元素分成大小大致相同的两个子集合,分别对两个集合进行排序,最终将排序好的子集合合并成所要求的排好序的集合。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000
void mergeer(int A[],int L[],int R[],int l,int r)
{
int i=0,j=0;
int k=0;
while(i<l&&j<r)//首元素比较
{
if(L[i]<=R[j])
{
A[k++]=L[i++];
}else{
A[k++]=R[j++];
}
}
///zuoyou剩余的部分复制进来
while(i<1)
{
A[k++]=L[i++];
}
//cout<<"#";
while(j<r)
{
A[k++]=R[j++];
}
}
void mergesort(int A[],int n)
{
if(n>1)
{
int mid=n/2;
int *left=(int *)malloc(sizeof(int)*mid);
int *right=(int *)malloc(sizeof(int)*(n-mid));
for(int i=0;i<mid;i++)
{
left[i]=A[i];
}
for(int i=mid;i<n;i++)
{
right[i-mid]=A[i];
}
// cout<<"*";
mergesort(left,mid);
mergesort(right,n-mid);
mergeer(A,left,right,mid,n-mid);
free(left);
free(right);
}
}
int main()
{
int a[maxn]={0};
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
mergesort(a,n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
return 0;
}
///input
//5
//2 3 6 5 1
3、集合最大元问题
在规模为n的数据元素集合中找出最大元。当n=2时,一次比较就可以找出两个数据元素的最大元和最小元。当n>2时,可以把n个数据元素分为大致相等的两半,一半有n/2个数据元素,而另一半有n/2个数据元素。 先分别找出各自组中的最大元,然后将两个最大元进行比较,就可得n个元素的最大元
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000
int finder(int *a,int n)
{
if(n==1)
{
return a[0];
}
if(n==2)
return max(a[0],a[1]);
int mid=n/2;
return max(finder(a,mid),finder(a+mid,n-mid));
}
int main()
{
int n;
cin>>n;
int a[maxn];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
cout<<finder(a,n);
return 0;
}
///input
//6
//2 3 5 6 4 1
4、循环赛日程表
2019年,德国甲级联赛刚刚落下帷幕。设有n支队伍参加循环赛,要求设计一个满足以下要求比赛日程表:
1)每支队伍必须与其它n-1支队伍各赛一次;
2)每支队伍一天只能赛一次。
输入:n=3
输出:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000
int a[maxn][maxn]={0};
void TableCreate(int Size,int val,int x,int y)
{
if (Size==2)
{
a[x][y]=val;
a[x+1][y]=val+1;
a[x][y+1]=val+1;
a[x+1][y+1]=val;
return ;
}
int Currentsize=Size/2;
if(Size%2!=0)
{
cout<<" WrongInput!"<<endl;
}
TableCreate(Currentsize,val,x,y);
TableCreate(Currentsize,val,x+Currentsize,y+Currentsize);
TableCreate(Currentsize,val+Currentsize,x+Currentsize,y);
TableCreate(Currentsize,val+Currentsize,x,y+Currentsize);
}
int main()
{
int n; //队伍数
cin>>n;
TableCreate(n,1,1,1);
for(int i = 1; i <=n; i++){
for(int j = 1; j <= n; j++){
printf("%3d",a[i][j]);
}
cout<<endl;
}
return 0;
}
五、实验结果与分析:
通过运行程序验证程序的正确性,给出程序运行结果,分析程序出现的bug的原因,调试程序过程种出现的错误和解决方法。