2020暑期牛客多校训练营第九场(I)Tournament(构造)

Tournament

原题请看这里

题目描述:

您正在安排比赛。 有n个团队。 每对球队都有 n ( n − 1 ) 2 \frac {n(n-1)} {2} 2n(n1)个比赛。 您可以每天安排比赛。 对于每支球队,它将在第一场比赛举行的当天到达,并在最后一场比赛结束后离开。
例如,有3个团队,日程表是 ( 1 , 2 ) , ( 1 , 3 ) , ( 2 , 3 ) (1,2),(1,3),(2,3) (1,2)(1,3)(2,3)。 一队将在第一天到达,在第二天离开。它将停留两天。 第二小组将停留三天。 第三队将停留两天。
您想找到一个时间表,以减少他们停留的天数。

输入描述:

第一行包含一个整数 T ( 1 ≤ T ≤ 30 ) T(1 \leq T \leq 30) T(1T30)-测试用例的数量。
对于每个测试用例,第一行包含一个整数 n ( 2 ≤ n ≤ 300 ) n(2 \leq n \leq 300) n(2n300)

输出描述:

对于每个测试用例,输出 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2行。 每行包含两个整数 ( u , v ) ( 1 ≤ u , v ≤ n ) (u,v)(1 \leq u,v \leq n) (uv)(1uvn)------您今天计划的比赛。

样例输入:

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,所以只需要输出任意一组答案。

A C AC AC C o d e Code Code:

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

你可能感兴趣的:(构造)