• 说明:这是武汉理工大学计算机学院【算法设计与分析】课程的第一次实验第二题:分治法与循环赛日程安排问题
  • 谨记:纸上得来终觉浅,绝知此事要躬行。 



一、问题描述:

设有【算法设计与分析】分治法与循环赛日程安排问题_武汉理工大学个选手要进行网球循环赛,要求设计一个满足以下要求的比赛日程表:

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

(2)每个选手一天只能赛一次。

 按此要求,可将比赛日程表设计成一个 n 行n-1列的二维表,其中,第 i 行第 j 列表示和第 i 个选手在第 j 天比赛的选手。       

二、问题分析:

按照分治的策略,可将所有参赛的选手分为两部分,n=2k个选手的比赛日程表就可以通过为【算法设计与分析】分治法与循环赛日程安排问题_分治法_02个选手设计的比赛日程表来决定。递归地执行这种分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单:只要让这2个选手进行比赛就可以了。

【算法设计与分析】分治法与循环赛日程安排问题_迭代_03

显然,这个求解过程是自底向上的迭代过程,其中左上角和左下角分别为选手1至选手4以及选手5至选手8前3天的比赛日程,据此,将左上角部分的所有数字按其对应位置抄到右下角,将左下角的所有数字按其对应位置抄到右上角,这样,就分别安排好了选手1至选手4以及选手5至选手8在后4天的比赛日程,如图(c)所示。具有多个选手的情况可以依此类推。

这种解法是把求解【算法设计与分析】分治法与循环赛日程安排问题_分治法_04个选手比赛日程问题划分成依次求解【算法设计与分析】分治法与循环赛日程安排问题_分治法_05【算法设计与分析】分治法与循环赛日程安排问题_算法设计与分析_06、…、【算法设计与分析】分治法与循环赛日程安排问题_分治法_04个选手的比赛日程问题,换言之,【算法设计与分析】分治法与循环赛日程安排问题_分治法_04个选手的比赛日程是在【算法设计与分析】分治法与循环赛日程安排问题_赛程安排_09个选手的比赛日程的基础上通过迭代的方法求得的。在每次迭代中,将问题划分为4部分:

(1)左上角:左上角为【算法设计与分析】分治法与循环赛日程安排问题_赛程安排_09个选手在前半程的比赛日程;

(2)左下角:左下角为另【算法设计与分析】分治法与循环赛日程安排问题_赛程安排_09个选手在前半程的比赛日程,由左上角加【算法设计与分析】分治法与循环赛日程安排问题_赛程安排_09得到,例如【算法设计与分析】分治法与循环赛日程安排问题_算法设计与分析_06个选手比赛,左下角由左上角直接加2得到,【算法设计与分析】分治法与循环赛日程安排问题_算法设计与分析_14个选手比赛,左下角由左上角直接加4得到;

(3)右上角:将左下角直接抄到右上角得到另【算法设计与分析】分治法与循环赛日程安排问题_赛程安排_09个选手在后半程的比赛日程;

(4)右下角:将左上角直接抄到右下角得到【算法设计与分析】分治法与循环赛日程安排问题_赛程安排_09个选手在后半程的比赛日程;

    算法设计的关键在于寻找这4部分元素之间的对应关系。

三、实验代码:

完整VS 2017项目:http​​s://github.com/cxh1231/Junior-Algorithm-CirculateScheduleProblem​

#include <iostream>
#include <math.h>
using namespace std;

int calendar[100][100]; //日程表数组

void GameTable(int k, int a[100][100]);
void PrintTable(int k, int a[100][100]);

int main()
{
int k;
cout << "输入K的值:" ;
cin >> k;
cout << "日程表如下" << endl;
GameTable(k, calendar);
PrintTable(k, calendar);
return 0;
}

void GameTable(int k, int a[100][100])
{
// n=2^k(k≥1)个选手参加比赛
//二维数组a表示日程安排,数组下标从1开始
int n = 2; //k=0,2个选手比赛日程可直接求得
//求解2个选手比赛日程,得到左上角元素
a[1][1] = 1; a[1][2] = 2;
a[2][1] = 2; a[2][2] = 1;
for (int t = 1; t < k; t++)
//迭代处理,依次处理2^2, …, 2^k个选手比赛日程
{
int temp = n; n = n * 2;
//填左下角元素
for (int i = temp + 1; i <= n; i++)
for (int j = 1; j <= temp; j++)
a[i][j] = a[i - temp][j] + temp;
//左下角元素和左上角元素的对应关系
//填右上角元素
for (int i = 1; i <= temp; i++)
for (int j = temp + 1; j <= n; j++)
a[i][j] = a[i + temp][(j + temp) % n];
//填右下角元素
for (int i = temp + 1; i <= n; i++)
for (int j = temp + 1; j <= n; j++)
a[i][j] = a[i - temp][j - temp];
}
}

void PrintTable(int k, int a[100][100])
{
double n = pow((double)2, k);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cout << a[i][j] << "  ";
}
cout << endl<<endl;
}
}

四、运行结果截图:

【算法设计与分析】分治法与循环赛日程安排问题_武汉理工大学_17

五、总结

NULL