一、问题描述
2019女排世界杯,比赛赛制采用12支队伍单循环,两两捉对厮杀一场定胜负,依次进行。
比赛开始把12个队分成AB两个组进行,当同组每一个选手都碰面以后,再重新分组进行比赛,确保12支队伍每两支都相遇一次,最终将根据先胜负场次后积分的排名顺序。
编程实现:输入球队的数量,得出比赛的对阵表。
二、问题分析
提醒:
1.参赛队伍的数量不同可能会产生轮空的现象(某个队伍当天没有比赛)
2.需要分成两种情况来考虑,存在轮空和不会存在轮空
不会存在轮空:2、4、8、16、32…
存在轮空:3、5、6、7、9…
讨论参赛队伍的对阵情况:
(1)2个队伍的时候,比赛对阵表如图所示:

a[0][0]=1;a[0][1]=2;
a[1][0]=2;a[1][1]=1;
(2)3个队伍的时候,会存在队伍轮空(当天不存在比赛)的情况。暂时不考虑。
(3)4个队伍的时候,对阵表如图所示

可知以4个队伍的比赛赛程安排是建立在黄色区域(两只队伍的对阵表)为已知基础上的,且满足已下关系:
蓝色区域:对应的位置是黄色区域的对应位置上的值+2
绿色区域:对应的位置是黄色区域的对应位置上的值+2
红色区域:对应的位置是黄色区域的对应位置上的值相等
//绿色
for(i=0;i<=1;i++)
for(j=0;j<=1;j++)
a[i][j+2]=a[i][j]+2;
//紫色
for(i=0;i<=1;i++)
for(j=0;j<=1;j++)
a[i+2][j]=a[i][j]+2;
//蓝色
for(i=0;i<=1;i++)
for(j=0;j<=1;j++)
a[i+2][j+2]=a[i][j];
(4) 5,6,7只队伍暂时不考虑(均存在轮空的情况)。先直接考虑8个队伍的对阵表

分治法实现:
把8个队伍的数据表示分成4小个区域。每个小区域又是由四个小区域构成。
区域之间的关系满足下列条件:
变化的值:
每一个小区域和左上角固定区域之间值的关系(蓝色区域:对应的位置是黄色区域的对应位置上的值+2)
三组for整体执行的次数:
(三次for构成一个完整的小区域,比如四只参赛队伍需要执行一次三组for。 整体执行次数则表示构成当前阵列需要执行多少次组合)

再考虑存在参赛队伍存在轮空的情况
(1)3个队伍的时候。

(2)5个队伍的时候。
5支队伍的对阵表等同于先计算8只队伍的参赛情况,然后去掉第5只队伍之后的队伍的对阵情况,再将前5只队伍的对阵列表中的含有第5只队伍的之后的队伍的情况置零(即轮空),则实现了5只队伍的对阵表
综上所述:
(1)我们可以先直接计算不存在轮空现象的参赛队伍的情况
(2)然后再通过置零的方法,实现存在轮空对阵的参赛队伍的情况
(3)从而实现输入队伍数量,输出对阵表
三、代码实现
1.实现效果
实现效果如下:

2.代码部分
#include<iostream>
#include<cmath>
#include <iomanip>
using namespace std;
int a[50][50];//对阵表最大容量
int b[6] = { 1,2,4,8,16,32};//不存在轮空现象的参赛队伍情况
//判断实际需要计算的对阵表(存在轮空现象会产生影响)
//比如 参赛队伍有5只 则只需要判断8只队伍的对阵表 然后将5只之后的情况 全部置零即可
//置零则表示当天对阵轮空
int compare(int N)
{
for (int i = 0; i < 7; i++)
{
if (b[i] >= N)
{
return b[i];
break;
}
}
}
void grouping(int N, int time)
{
int i, j, k;
//2个队伍的比赛对阵表作为已知值
a[0][0] = 1; a[0][1] = 2;
a[1][0] = 2; a[1][1] = 1;
for (k = 1; k <= (log(time) / log(2)) - 1; k++)
{
//每次变化的值t等于2的循环执行次数 t = pow(2,k)
int t = pow(2, k);
//绿色部分
for (i = 0; i <= t - 1; i++)
for (j = 0; j <= t - 1; j++)
a[i][j + t] = a[i][j] + t;
//蓝色部分
for (i = 0; i <= t - 1; i++)
for (j = 0; j <= t - 1; j++)
a[i + t][j] = a[i][j] + t;
//红色部分
for (i = 0; i <= t - 1; i++)
for (j = 0; j <= t - 1; j++)
a[i + t][j + t] = a[i][j];
}
}
int main()
{
int i, j, N;
cout << "请输入队伍数量:";
cin >> N;
int time = compare(N);//time 统计队伍数量 比如6只队伍 需要先统计8只队伍的情况 然后将6之后的队伍情况置零即可
grouping(N, time);
//N 多少只参赛队伍
//time 一共需要比赛的天数
//零则表示当天对阵轮空
for (j = 0; j < time; j++)
cout << "\t第" << j + 1 << "天";
cout << endl;
for (i = 0; i < N; i++)
{
cout << "队伍" << i + 1;
for (j = 0; j < time; j++)
{
if (a[i][j] > N)
{
a[i][j] = 0;
}
printf("\t%3d", a[i][j]);
}
printf("\n");
}
return 0;
}
代码小白,仅作学习记录📝