2020牛客暑期多校训练营(第十场) Tournament

原题
题目描述
您正在安排比赛。有 n n n个球队。 每一对球队有 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1)个比赛。 每天安排一场比赛。 对于每支球队,它将在第一场比赛举行的当天到达,并在最后一场比赛结束后离开。
例如,有3个团队,日程表是 ( 1 , 2 ) (1,2) (12) ( 1 , 3 ) (1,3) (13) ( 2 , 3 ) (2,3) (23)。 一队将在第一天到达,在第二天离开。它将停留两天。 第二小组将停留三天。 第三队将停留两天。
求一个安排表,以减少他们停留的总天数。
样例
输入

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
#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;
}

你可能感兴趣的:(2020牛客暑期多校训练营(第十场) Tournament)