题目:
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
用分治算法生成循环赛日程表(1到2的n次方个人)
输入
一个小于等于7的正整数n
输出
循环赛日程表(1到2的n次方个人)
输入样例
3
输出样例
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
我们采用分治策略,将所有的选手分为两半,n个选手的比赛日程表可以通过为n / 2个选手设计的比赛日程表来确定。递归的用一分为二的策略对选手进行分割,直到只剩下两个选手时,比赛日程表的制定就变得简单。这时只让两个选手进行比赛就可以。
在比赛安排中,左上角与左下角的2小块的分别为选手1到选手4 以及选手5 之选手8前3天的比赛日程。据此将左上角小块中的所有数字按其相对位置抄到右下角,将左下角小块的元素按其相对位置抄到右上角这样就安排好了选手1至选手4以及选手5至选手8在后4天的比赛日程。
#include <iostream>
using namespace std;
const int maxn = 10005;
int a[maxn][maxn];
void dfs(int length,int n)
{
//初始正确;
a[1][1] = 1;
a[1][2] = 2;
a[2][1] = 2;
a[2][2] = 1;
for(int k = 1;k <= n;k ++)
{
int tmp = length;
length *= 2;
for(int i = tmp + 1;i <= length;i ++)
{
for(int j = 1;j <= tmp;j ++)
{
a[i][j] = a[i - tmp][j] + tmp;
}
}
for(int i = tmp + 1;i <= length;i ++)
{
for(int j = 1;j <= tmp;j ++)
{
a[i - tmp][j + tmp] = a[i][j];//左下角抄到右上角。
}
}
for(int i = 1;i <= tmp;i ++)
for(int j = 1;j <= tmp;j ++)
{
a[i + tmp][j + tmp] = a[i][j];//左上角抄到右下角。
}
}
}
int main()
{
int n,k;
cin >> n;
k = 1 << n;
dfs(2,n);
for(int i = 1;i <= k;i ++)
{
for(int j = 1;j <= k;j ++)
{
cout << a[i][j];
if(j == k)cout << endl;
else cout <<" ";
}
}
return 0;
}