算法分析与设计——2.5 循环赛日程表

问题描述:设有n=2^k个运动员要进行网球循环赛。现在要设计一个满足以下条件的比赛日程表。 

(1)每个选手必须要与其他n-1个选手各赛一次;

(2)  每个选手一天只能赛一场;

(3)  循环赛赛程是n-1天。

算法设计:设计一张循环赛日程表。

问题输入:输入k值。

问题输出:输出n×n的赛程表。

问题思路:可以采用分治递归解决,也可以采用分治非递归算法。

A. 分治递归方案

1 2 3 4 5 6 7 8
2 1 4 3 6 5 8 7
3 4 1 2 7 8 5 6
4 3 2 1 8 7 6 5
5 6 7 8 1 2 3 4
6 5 8 7 2 1 4 3
7 8 5 6 3 4 1 2
8 7 6 5 4 3 2 1

以上是一个排好的循环赛日程表。我们发现当k=1时,在这个2x2的表格里,a[0][0]=a[1][1],a[1][0]=a[0][1]。也就是对角线上的表格元素相同,当k=2时,在4x4的表格里,对角线上的2x2的小表格元素相同。随之扩展到当k=n时,在2^nx2^n的表格里,对角线上的2^(n-1)x2^(n-1)的小表格元素相同。也就是说,任意给定一个k值所构成的nxn的表格的元素内容,都可以直接用这个表格的前(n/2)x(n/2)上的元素去复制得到后(n/2)x(n/2)的元素,即用左上表格复制得到右下表格,左下表格得到右上表格。也就是把此问题划分成了2个子问题。且并不存在公共子问题。边界条件就是当k=0时n=1,不用执行操作。所以满足的递归方程为:

T(n)=O(1)  n=1;

T(n)=2T(n/2)+O(n^2)    n>1;

T(n)=O(n^2)。

代码如下;

#include
#include
using namespace std;
//分治递归
void copy(int **arr,int x1, int y1, int x2, int y2, int n)//二维数组指针
{//xia
	for(int i=0;i> k;
	int n = 1;
	for (int i = 1; i <= k; i++)
		n *= 2;
	int **arr = new int*[n];//二维数组指针初始化
	for (int i = 0; i < n; i++) {
		arr[i] = new int[n];
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++)
		{
			if (j == 0)arr[i][j] = i + 1;
			else
				arr[i][j] = 0;
		}
	}
	Table(arr,0, 0, n);
	print(arr,n);
	cout << "The run time is:" << (double)clock() / CLOCKS_PER_SEC << "us" << endl;
	return 0;

}

 运行结果

算法分析与设计——2.5 循环赛日程表_第1张图片

B. 非递归算法

非递归算法可以先输入一列/行原始数据,通过对位copy,一步一步迭代出总方案。最坏情况下的时间复杂度为O(n^2)。

#include
#include
using namespace std;

#define N 1024
int arr[N][N];

void copy(int x1, int y1, int x2, int y2, int n)
{//xia
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
		{
			arr[x2 + i][y2 + j] = arr[x1 + i][y1 + j];
		}
}

void Table(int k)
{
	int n = pow(2, k);
	for (int i = 0; i < n; i++)
		arr[i][0] = i + 1;
	for (int i = 2; i <= n; i *= 2)
	{
		for (int j = 0; j < n; j += i)
		{
			int s = i / 2;
			copy(j, 0, j + s, s, s);
			copy(j + s, 0, j, s, s);
		}
	}
}

void print(int n)
{
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++)
		{
			cout.setf(std::ios::left);
			cout.width(5);
			cout << arr[i][j];
		}
		cout << endl;

	}
}

void matchtable(int k)
{
	int m = 1;
	int n = pow(2, k);
	for (int i = 0; i < n; i++)
		arr[i][0] = i + 1;
	for (int s = 0; s < k; s++)
	{
		n /= 2;
		for (int t = 0; t < n; t++)
		{
			for (int j = m; j < 2 * m; j++)
			{
				for (int i = m; i < 2 * m; i++)
				{
					arr[i - m + 2 * t*m][j] = arr[i + 2 * t*m][j - m];
					arr[i + 2 * t*m][j] = arr[i - m + 2 * t*m][j - m];
				}
			}
		}
		m *= 2;
	}
}

int main()
{
	int k;
	cout << "输入k:";
	cin >> k;
	int n = pow(2, k);
	Table(k);
	print(n);
	cout << " 另一种" << endl;
	matchtable(k);
	print(n);
	return 0;
}

输出结果

算法分析与设计——2.5 循环赛日程表_第2张图片

你可能感兴趣的:(算法,c++,分治算法,数组,指针)