问题描述
设有n=2k个运动员要进行羽毛球循环赛,现要设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其它n-1个选手各赛一次;
(2)每个选手一天只能比赛一次;
(3)循环赛一共需要进行n-1天。
由于n=2^k,显然n为偶数。
按分治策略,将所有的选手分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了。
分治法求解思路
(1)如何分,即如何合理地进行问题的分解?
一分为二
(2)如何治,即如何进行问题的求解?
进行合并
(3)问题的关键——发现循环赛日程表制定过程中存在的规律性。
循环赛日程表算法描述:
Void Round_Robin_Calendar(int k, int **a)
{ int n=1,i,j,s;
n = 1<<k;
for(i=1;i<=n;i++) a[1][i]=i;
int m=1;
for(s=1;s<=k;s++) //问题划分的次数
{ n/=2;
for(int t=1;t<=n;t++) //每一部分的问题进行单元格的填充
for(i=m+1;i<=2*m;i++) //控制行
for(j=m+1;j<=2*m;j++) //控制列
{ a[i][j+(t-1)*m*2]=a[i-m][j+(t-1)*m*2-m];
a[i][j+(t-1)*m*2-m]=a[i-m][j+(t-1)*m*2];
}
m*=2;
}
}
代码实现
#include <iostream>
using namespace std;
void Round_Robin_Calendar(int **a,int k);
int main()
{
int n,k;
cin>>k;
n = 1<<k;
int **a = new int *[n];
for(int i = 1 ; i <= n ; i++)
a[i] = new int[n];
Round_Robin_Calendar(a, k);
for(int i = 1 ; i<= n ; i++)
{
for(int j = 1 ; j <= n ; j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
return 0;
}
void Round_Robin_Calendar(int **a,int k)
{
int n;
n = 1<<k;
for(int i = 1 ; i <= n ; i++) a[1][i] = i;
int m = 1;
for(int s = 1 ; s <= k ; s++)
{
n /= 2;
for(int t = 1 ; t <= n ; t++)
for(int i = m+1 ; i <= 2*m ; i++)
for(int j = m+1 ; j <= 2*m ; j++)
{
a[i][j+(t-1)*2*m] = a[i-m][j+(t-1)*2*m-m];
a[i][j+(t-1)*2*m-m] = a[i-m][j+(t-1)*2*m];
}
m *= 2;
}
}