实验一
实验名称:递归与分治算法设计 | |
实验室名称:906 |
实验台号:11 |
学生姓名: 周唯唯 |
专业班级: 15-计科-1 |
指导教师:李艳娟 |
实验日期:2017-9-18 |
一、 实验目的
通过棋盘覆盖问题或合并排序问题及集合最大元问题,掌握分治算法的基本思想,掌握分治算法的设计步骤及用递归技术实现分治策略。
二、实验仪器及环境:
PC计算机;windows XP操作系统、Visual C++6.0
二、 实验内容及结果
1、 棋盘覆盖问题
在一个2k×2k 个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
#include<iostream>
using namespacestd;
int tile = 1;//全局变量骨牌编号
intBoard[4][4];//棋盘
voidChessBoard(int tr,int tc,int dr,int dc,int size);
int main()
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
Board[i][j] = 0;
}
}
ChessBoard(0,0,0,1,4);
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
cout<<Board[i][j]<<"";
}
cout<<endl;
}
}
/**
* tr : 棋盘左上角的行号,tc棋盘左上角的列号
* dr : 特殊方格左上角的行号,dc特殊方格左上角的列号
* size :size = 2^k 棋盘规格为2^k*2^k
*/
voidChessBoard(int tr,int tc,int dr,int dc,int size)
{
if(size == 1)
{
return;
}
int t = tile++;//L型骨牌编号
int s = size/2;//分割棋盘
//覆盖左上角子棋盘
if(dr<tr+s && dc<tc+s)//特殊方格在此棋盘中
{
ChessBoard(tr,tc,dr,dc,s);
}
else//特殊方格不在此棋盘中
{
//用编号为t的骨牌覆盖右下角
Board[tr+s-1][tc+s-1] = t;
//覆盖其余方格
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//特殊方格不在此棋盘中
{
//用编号为t的骨牌覆盖左下角
Board[tr+s-1][tc+s] = t;
//覆盖其余方格
ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
}
//覆盖左下角子棋盘
if(dr>=tr+s && dc<tc+s)//特殊方格在此棋盘中
{
ChessBoard(tr+s,tc,dr,dc,s);
}
else//特殊方格不在此棋盘中
{
//用编号为t的骨牌覆盖右上角
Board[tr+s][tc+s-1] = t;
//覆盖其余方格
ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
}
//覆盖右下角子棋盘
if(dr>=tr+s && dc>=tc+s)//特殊方格在此棋盘中
{
ChessBoard(tr+s,tc+s,dr,dc,s);
}
else//特殊方格不在此棋盘中
{
//用编号为t的骨牌覆盖左上角
Board[tr+s][tc+s] = t;
//覆盖其余方格
ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
输入:
4*4的矩阵 特殊位置是(0,1)
输出:如图
2、合并排序问题
对n个元素组成的序列进行排序。
基本思想:将待排序元素分成大小大致相同的两个子集合,分别对两个集合进行排序,最终将排序好的子集合合并成所要求的排好序的集合。
#include <stdio.h>
#include <stdlib.h>
void Merge(int *c ,int *d,int l,intm,int r)
{
int i=l;
int j=m+1;
int k=l;
while((i<=m)&&(j<=r))
{
if(c[i]<=c[j])
{
d[k++]=c[i++];
}
else
{
d[k++]=c[j++];
}
}
int q;
if(i<m)
{
for(q=i;q<=m;q++)
{
d[k++]=c[q];
}
}
else
{
for(q=j;q<=r;q++)
{
d[k++]=c[q];
}
}
}
void MergeSort(int *a,int *b,intleft,int right)
{
if(left<right)//至少有两个元素 一直要分到为1
{
int i=(left+right)/2;
MergeSort(a,b,left,i);
MergeSort(a,b,i+1,right);
Merge(a,b,left,i,right);//合并到b
int j;
for(j=left;j<=right;j++)//每次合并一次就给a更新
{
a[j]=b[j];
}
}
}
int main()
{
int n,i;
printf("请输入数组元素的个数:");
scanf("%d",&n);
int *a=(int *)malloc(sizeof(int)*n);
int *b=(int *)malloc(sizeof(int)*n);//临时数组
printf("请输入要排序的数组:");
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
MergeSort(a,b,0,n-1);
//排序后
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
return 0;
}
输入:
数组元素个数6
待排序的数组元素为:0 4 8 2 6 9
输出:
合并排序后结果为:0 2 4 6 8 9
3、集合最大元问题
在规模为n的数据元素集合中找出最大元。当n=2时,一次比较就可以找出两个数据元素的最大元和最小元。当n>2时,可以把n个数据元素分为大致相等的两半,一半有n/2个数据元素,而另一半有n/2个数据元素。 先分别找出各自组中的最大元,然后将两个最大元进行比较,就可得n个元素的最大元
#include <stdio.h>
#include <stdlib.h>
int cal(int *a,int left,int right)
{
if(left==right)
return a[left];
else if(left+1==right)
returna[left]>a[right]?a[left]:a[right];
else
{
intmax_left=cal(a,left,(left+right)/2);
intmax_right=cal(a,(left+right)/2+1,right);
returnmax_left>max_right?max_left:max_right;
}
}
int main()
{
int n;
printf("请输入数组的个数:");
scanf("%d",&n);
int *a=(int*)malloc(sizeof(int)*n);
printf("请输入原始数据:");
int i;
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
printf("最大的数为:%d",cal(a,0,n-1));
return 0;
}
输入:
请输入数组的个数:6
请输入原始数据:04 8 2 1 3
输出:
最大的数为:8
四、实验心得体会:(包括遇到的问题及解决办法)
1.棋盘覆盖
注意0为初始化的矩阵值
tile从1开始
2.合并排序:
问题(1):一开始不知道临时数组b该在哪里声明
解决:int *b=(int *)malloc(sizeof(int)*n);//临时数组应在调用Mergesort()之前就开辟空间,然后调用合并排序传参,这样可以节省空间。
问题(2):什么时候将数组复制
全部分好以后,每次合并一次就给a更新,然后再继续合并
3.集合最大元:
问题:动态开辟内存空间应该怎么传递参数
解决:直接将指针作为参数传递,使函数中的指针临时指向所开辟的内存
五、指导教师意见及成绩
签名:
年月日