2020牛客暑期多校训练营Tournament(构造)

本文探讨了一种优化比赛调度的方法,旨在最小化所有参赛队伍在场地停留的总时间。通过将队伍分为两组并采用特定的配对策略,实现了均衡分配比赛时间的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Tournament

题目描述

在这里插入图片描述

样例

input:
2
3
4
output:
1 2
1 3
2 3
1 2
1 3
1 4
2 3
2 4
3 4

题目大意

n n n支队伍两两之间比赛一场,则进行 n ( n − 2 ) 2 \frac{n(n-2)}{2} 2n(n2)场。现每支队伍会从他们要比赛的第一天开始直到他们的比赛的最后一场为止,即安排中他们队伍最后出现的那天为止,都会待在比赛场地里。
现你可以安排比赛顺序,要求如何安排会使得所有队伍待在场地里的时间总合最小。

分析

首先想到的是:
f o r ( i    f r o m    1 → n ) for(i\,\,from\,\,1\to n) for(ifrom1n)
f o r ( j    f r o m    i + 1 → n ) \qquad for(j\,\,from\,\,i+1\to n) for(jfromi+1n)
o u t p u t ( i , j ) ; \qquad\qquad output(i,j); output(i,j);
显然,这一策略是很劣的,因为1队虽然时间很短,但是其他队伍的时长完全拉大了整个的时长。分析后易得可以发现,我们需要使得每支队伍都是基本差不多的时长,即保证没有队伍受到优待。

接下来是官方的策略:
首先将所有的队伍分成两个部分,然后前面是 1 ∼ n 2 1\sim \frac{n}{2} 12n,后面是 n 2 + 1 ∼ n \frac{n}{2}+1\sim n 2n+1n。那么只要考虑中间的打法就可以了。接下来我们以 n = 10 n=10 n=10为例。
显然我们之前是 1 ∼ 5 1\sim 5 15的比赛,那么我们希望10号队伍最迟来(因为后面10号肯定是最后走的),又希望1号最早走(因为前面1号肯定最早来的),所以中间肯定是 ( 1 , 10 ) (1,10) (1,10)
然后考虑前面,通过上面的思考,我们得出:希望9号是6~9之中来得最迟的,希望……所以前面是 ( 1 , 9 ) (1,9) (1,9)。然后是 ( 1 , 8 ) , ( 2 , 8 ) (1,8),(2,8) (1,8),(2,8),依此类推……
然后考虑后面,同样的,我们6~10已经全部出现了,那么是希望1先走,所以把1和10打了,那么接下来是2了,同样的2和10,9打,然后3和10,9,8打……
这样我们就得出了中间的策略,那么根据刚才对前后的要求,显然,1 ~5和6 ~10也要像中间那样搞。
那么我们就可以得出:

for(i=2;i<=n/2;++i)
    for(j=1;j<i;++j)
        printf("%d %d\n",j,i);
for(i=n/2+1;i<n;++i)
    for(j=1;j<=n-i;++j)
        printf("%d %d\n",j,i);
for(i=1;i<=n/2;++i)
    for(j=n-i+1;j<=n;++j)
        printf("%d %d\n",i,j);
for(i=n/2+1;i<n;++i)
    for(j=i+1;j<=n;++j)
        printf("%d %d\n",i,j);  

这样的比较好理解,但是多试几组可以发现其实前面和中间的前半部分以及后面和中间的后半部分是可以合并的,这样代码比较短,但是难理解。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	int n,t;scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=2;i<=n;i++)
			for(int j=1;j<=min(i-1,n-i);j++)
				printf("%d %d\n",j,i);
		printf("1 %d\n",n);
		for(int i=2;i<n;i++)
			for(int j=max(n-i+1,i+1);j<=n;j++)
				printf("%d %d\n",i,j);
	}
}

END

较长的代码取自DNdalao。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值