Tournament
题目描述:
您正在安排比赛。 有n个团队。 每对球队都有
个比赛。 您可以每天安排比赛。 对于每支球队,它将在第一场比赛举行的当天到达,并在最后一场比赛结束后离开。
例如,有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",i,j);
交上去就是一发WA…
先WA一发清醒一下后再仔细分析一下题目:
如果每次我们让第一队先走,那么我们会发现标号越大的队伍住的天数越多,这明显是不合理的…
首先我们想到:1队越早走,后面的队伍住的总时间就越长,所以我们要尽量折中每个队伍的住的时间。
于是我们就想到如下的构造方法:
- 首先把n个人分成两半
- 然后让前一半的人开始打比赛
- 然后让前一半的人和后一半的人打比赛
- 然后后一半的人开始打比赛
按照上面的WA的暴力代码和上面的构造策略,以n=6为例:
暴力: 构造:
1 2 1 2
1 3 1 3
1 4 2 3
1 5 1 4
1 6 2 4
2 3 3 4
2 4 1 5
2 5 2 5
2 6 3 5
3 4 4 5
3 5 1 6
3 6 2 6
4 5 3 6
4 6 4 6
5 6 5 6
明显构造的方法较优。
但是也不止这么一种构造方法,如果两个比赛顺序换一换是等价的当然也可以。
这题是spj,所以只需要输出任意一组答案。
:
#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=2;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=n-i+1;j<=n;++j)
printf("%d %d\n",i,j);
for(int i=n/2+1;i<n;++i)
for(int j=i+1;j<=n;++j)
printf("%d %d\n",i,j);
}
}