分治法编程求解循环日程安排问题(c/c++实现)

250 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

1.问题描述

设有n=2k个选手要进行网球循环赛,设计一个满足以下要求的比赛日程表:(1)每个选手必须与其他n-1个选手各赛一次。(2)每个选手一天只能赛一次。(3)循环赛在n-1天之内结束。

1.1产生的疑问

有没有可能因为是随机配,打到后面,没跟A打过的人跟别人打了,然后A轮空了。这种事情有可能发生吗?

2.思路及想法

  1. 每一天每一个球员跟哪个球员打,这样一个二维数组可以记录的下。
  2. 但是需要额外多一个二维数组,两两之间打过的要做记录,而且表格要不断进行更新。
  3. 今天这位选手打了没可以直接借用第一点的那个二维数组,值不为0就是打过了。因为是两两配对,所以2^k次方个人每天都能确保有一场比赛。

3.什么是分治法

分治法指的是将原问题递归地分成若干个子问题,直到子问题满足边界条件,停止递归,将子问题逐个解决(一般是同种方法),将已经解决的子问题合并,最后,算法会层层合并得到原问题的答案。

3.1分治算法步骤

  1. 分:递归地将问题分解为各个的子问题(性质相同的,相互独立的子问题)。  
  1. 治:将这些规模更小的子问题逐个击破。
  1. 合:将已解决的问题逐层合并,最终得出原问题的解。

3.2分治算法适用条件

  1. 问题的规模缩小到一定的规模就可以较容易地解决。
  2. 问题可以分解为若干个规模较小的模式相同的子问题,即该问题具有最优子结构性质。
  3. 合并问题分解出的子问题的解可以得到问题的解。
  4. 问题所分解出的各个子问题之间是独立的,即子问题之间不存在公共的子问题。

4代码实现

#include<iostream>
#include<math.h>
using namespace std;
int a[100][100];//定义一百行一百列
void xunhuan(int x,int y,int n)
{
	int mid = n / 2;
	if (n >= 4)
	{
		xunhuan(x, y, mid);//分解后第一部分左上角数字的位置
		xunhuan(x, y + mid, mid); //分解后第二部分左上角数字的位置
	}
	for (int i = x+mid; i < x + n; i++)
	{
		for (int j = y; j < y + mid ; j++)
		{
			a[i ][j ] = a[i - mid][j+mid];
		}
	}
	for (int i = x + mid; i < x + n; i++)
	{
		for (int j = y+mid; j <y + n; j++)
		{
			a[i][j] = a[i - mid][j - mid];
		}
	}
}
int main()
{
	int k;
	cin >> k;
	int n;
	n = pow(2, k);//人数
	for (int j = 1; j <= n; j++)//将第一列先赋值
	{
		a[1][j] = j;
	}
	xunhuan(1, 1, n);
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			cout << a[i][j]<<" ";
		}
		cout << endl;
	}
}