牛客多校10 - Tournament(找规律)

题目链接:点击查看

题目大意:现在有 n 个队伍参加比赛,任意两个队伍之间都要进行一次比赛,也就是共需要进行 n * ( n - 1 ) / 2 次比赛,对于每个队伍来说,必须要在第一场比赛的时候到达赛场,在最后一场比赛结束后离开赛场,在赛场上呆的时间即为贡献,现在求出一种比赛的安排顺序,使得每个队伍的贡献之和最小

题目分析:可以自己手玩一下找找规律,这里以 n = 6 为例,画个图:

上图中表示了 n * ( n - 1 ) / 2 场比赛按照升序排列后,也就是按照红色箭头的方向依次比赛,相信肯定有不少同学在看完样例后以为这样是最优的,于是莽了一发,结果得到的是答案错误吧 

我来一步一步优化一下整体序列,使得每次都变的最优吧,首先求一下当前情况下,每个队伍需要在赛场上滞留的天数

接下来我们不难发现,如果尝试将 ( 2 , 3 ) 这个点移到 ( 1 , 3 ) 之后,可以使得队伍 1 的贡献加一,队伍 2 和队伍 3 的贡献不变,队伍 4 , 5 , 6 的贡献减一,显然这样是更优的,于是我们移动一下

在此基础上,我们发现前移 ( 2 , 4 ) 也是可以让贡献减少,于是再次更新顺序

到此为止,可以得到当 n = 6 的答案序列了,是不是没有看出任何规律?好,那我们继续将 ( 2 , 5 ) , ( 2 , 6 ) 和 ( 3 , 4 ) 分别移动到相应的位置,看看结果会发生什么样的变化

 

到此为止,差不多就可以稍微总结一下结论或者规律了, 首先默认初始时比赛的顺序为最初的升序排列,对于一比赛不妨设为 ( i , j ) 满足 i < j ,如果将 ( i , j ) 前移(先不要管将其移动到什么位置),则对整体的贡献就是,i 前面的队伍,贡献会 +1 ,j 后面的队伍,贡献会 -1,用公式表达的话,( i , j ) 前移的贡献就是 sum += ( i - 1 ) - ( n - j ) ,也就是说,对于一场比赛我们可以分为三种情况:

  1. ( i - 1 ) - ( n - j ) < 0:这场比赛放在前面最优
  2. ( i - 1 ) - ( n - j ) == 0:这场比赛放在中间最优
  3. ( i - 1 ) - ( n - j ) > 0:这场比赛放在后面最优

推广一下发现这个结论对所有的 ( i , j ) 都适用,剩下的就是在三个部分中,各自排序的问题了,在上面手动模拟后,看的出中间部分和后面部分按照升序排列就好了,而前半部分需要按照 j 的升序排列,当 j 相同时再按照 i 的升序排列

证明的话我也不会,毕竟是比赛时找规律乱搞出来的,不过看完之后应该感觉还是比较有道理是吧?

实现就比较简单了

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;
 
typedef long long LL;
 
typedef unsigned long long ull;
 
const int inf=0x3f3f3f3f;
 
const int N=310;

bool maze[N][N];

void init(int n)
{
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			maze[i][j]=true;
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int w;
	cin>>w;
	while(w--)
	{
		int n;
		scanf("%d",&n);
		init(n);
		vector<pair<int,int>>ans;
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)
			{
				if(i-1<n-j)
				{
					ans.emplace_back(i,j);
					maze[i][j]=false;
				}
			}
		sort(ans.begin(),ans.end(),[&](pair<int,int>a,pair<int,int>b)
		{
			if(a.second!=b.second)
				return a.second<b.second;
			return a.first<b.first;	
		});
		for(int i=1;i<=n;i++)
			for(int j=i+1;j<=n;j++)
				if(maze[i][j])
					ans.emplace_back(i,j);
		for(auto it:ans)
			printf("%d %d\n",it.first,it.second);
	}

















   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/107924613
今日推荐