题目链接:http://acm.uestc.edu.cn/#/problem/show/1607
解法:
构造法:蛇形安排赛程表
算法复杂度:O(N^2)
将1-N排成两竖列,每一轮同一行的为对手
保持1的位置不变,其他位置按顺(逆)时方向依次旋转
1 6 1 2 1 3 1 4 1 5
2 5 3 6 4 2 5 3 6 4
3 4 4 5 5 6 6 2 2 3
1 N
2 N-1
3 N-2
. .
. .
. .
N/2 N/2+1
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100;
int n, a[maxn][2];
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n/2;i++){
a[i][0]=i;
a[i][1]=n-i+1;
}
int t;
for(int i=1; i<n; i++){
for(int j=1; j<=n/2; j++){
if(j!=1) putchar(' ');
printf("%d %d", a[j][0],a[j][1]);
}
putchar('\n');
t = a[2][0];
for(int j=2; j<n/2; j++){
a[j][0]=a[j+1][0];
}
a[n/2][0]=a[n/2][1];
for(int j=n/2; j>=2; j--){
a[j][1]=a[j-1][1];
}
a[1][1]=t;
}
}
return 0;
}
UESTC还提供了一种DP的方法
DP做法
算法复杂度:O(N^3)
如果我们知道4支队伍的赛程表,就可以推出8支队伍的赛程表
1-2 3-4
1-3 2-4
1-4 2-3
第一部分:将8支队伍分成两组进行组内对抗
1-2 3-4 5-6 7-8
1-3 2-4 5-7 6-8
1-4 2-3 5-8 6-7
第二部分:两组队伍进行组间对抗
1-5 2-6 3-7 4-8
1-6 2-7 3-8 4-5
1-7 2-8 3-5 4-6
1-8 2-5 3-6 4-7
所以,我们如果能知道N(N为偶数)支球队的赛程表,就可以推出2*N支球队的赛程表
如果N为奇数,N支球队的赛程表和2*N支球队的赛程表该怎么推呢?
N为奇数的话,赛程表也得进行N轮,每轮会有一支球队轮空
比如说N=3(可假想N=4,多一个对手0,与0对阵算作轮空)
第一轮:1-2 3(轮空)
第二轮:1-3 2(轮空)
第三轮:2-3 1(轮空)
我们知道了三支球队的赛程表,六支球队的赛程表该这么转移
6支球队分成两组 先进行组内对抗
1-2 3(轮空) 4-5 6(轮空)
1-3 2(轮空) 4-6 5(轮空)
2-3 1(轮空) 5-6 4(轮空)
但是,我们不允许两支球队轮空,就得把分别在组内对抗按道理应轮空的两支球队对阵
1-2 4-5 3-6
1-3 4-6 2-5
2-3 5-6 1-4
再进行组间对抗
1-4 2-5 3-6 (这里的对阵在组内对抗进行过了,应去掉)
1-5 2-6 3-4
1-6 2-4 3-5
我理解了这个递推思路,但是思考了下发现不会写这个方法。。就先放这里吧。