原题
题目描述
您正在安排比赛。有
n
n
n个球队。 每一对球队有
n
(
n
−
1
)
2
\frac{n(n-1)}{2}
2n(n−1)个比赛。 每天安排一场比赛。 对于每支球队,它将在第一场比赛举行的当天到达,并在最后一场比赛结束后离开。
例如,有3个团队,日程表是
(
1
,
2
)
(1,2)
(1,2),
(
1
,
3
)
(1,3)
(1,3),
(
2
,
3
)
(2,3)
(2,3)。 一队将在第一天到达,在第二天离开。它将停留两天。 第二小组将停留三天。 第三队将停留两天。
求一个安排表,以减少他们停留的总天数。
样例
输入
2
3
4
输出
1 2
1 3
2 3
1 2
1 3
1 4
2 3
2 4
3 4
思路
首先,我们看到这个样例,会想到以下这个暴力代码
:
:
:
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
printf("%d %d\n",i,j);
其实这并不是最优的方案。我们举一个
n
=
6
n=6
n=6的例子
:
:
:
按照刚才那个策略,方案应该是以下这个样子
:
:
:
1 2
1 3
1 4
1 5
1 6
2 3
2 4
2 5
2 6
3 4
3 5
3 6
4 5
4 6
5 6
其实仔细思考一下,其实这个方案只保证了 1 1 1团队停留的时间短,而比如说 6 6 6团队和 5 5 5团队,停留的时间就很长,这就类似于 1 1 1换 2 2 2或 1 1 1换 3 3 3的情况,并不是最优解。所以我们要把 1 1 1团队停留的时间尽量拉长, 6 6 6和 5 5 5团队停留的时间缩短,从而来保证每个团队停留的时间尽可能接近。一拍脑袋,我们会想到一下这个策略 : : :
- 首先把 n n n个人分成 n 2 \frac{n}{2} 2n个人和 n 2 \frac{n}{2} 2n个人。
- 然后让前 n 2 \frac{n}{2} 2n个人开始打比赛。
- 接着让前 n 2 \frac{n}{2} 2n个人开始和后 n 2 \frac{n}{2} 2n个人打比赛。
- 然后让后 n 2 \frac{n}{2} 2n个人开始打比赛。
还是举 n = 6 n=6 n=6这个例子,方案就变成了这样 : : :
1 2
1 3
2 3
1 4
2 4
1 5
1 6
2 6
2 5
3 6
3 5
3 4
4 5
4 6
5 6
这样团队停留时间的总和就是最小的。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+10;
int t,n;
int main()
{
for(scanf("%d",&t);t--;)
{
scanf("%d",&n);
for(int i=1;i<=n/2;i++)for(int j=1;j<i;j++)printf("%d %d\n",j,i);
for(int i=n/2+1;i<=n;i++)for(int j=1;j<=n-i;j++)printf("%d %d\n",j,i);
for(int i=1;i<=n/2;i++)for(int j=1;j<=i;j++)printf("%d %d\n",i,n-j+1);
for(int i=n/2+1;i<n;i++)for(int j=i+1;j<=n;j++)printf("%d %d\n",i,j);
}
return 0;
}