【题解】洛谷P1309 瑞士轮(归并排序)

看了一眼数据大小,我们可以知道用快排肯定会TLE,自己手写模拟试了试,果真只得了60分,因此我们需要改进排序算法。

这里我们可以用归并排序(时间复杂度O(N)),归并排序的思想就是对两个有序的数组进行操作,然后开另一个数组为两个数组大小之和。设两个指针p1,p2,开始初始化为1。当两个指针中的任何一个没有到最后时,就比较指针所指的数,将更大的数进入第三个数组,然后把该数所在的原数组的指针后移,反复进行上述操作。这可以节省快排的时间,但注意需要清零。在这道题里,对于这两个数组,我们把赢的放一起、输的放一起(都用结构体),由于在在过程中我们合并的数组排列是有序的,所以将两个人进行比较后,胜者放在胜者组,将胜者放一起也肯定是有序的(可以自己想想)。如果指针到头了,那我们就把没到头的那一个数组的后面的所有数都搬到合并数组的空位,然后就得到有序的合并数组了。注意对指针进行清零操作。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200010;
int n,r,q;
struct player
{
	int s; //score
	int p; //power
	int num; //number
}a[maxn],win[maxn],lose[maxn],c[maxn];
bool cmp(const player &a,const player &b)
{
	if(a.s!=b.s) return a.s>b.s;
	else return a.num<b.num;
}
int p1,p2;
int main()
{
	scanf("%d%d%d",&n,&r,&q);
	for(int i=1;i<=2*n;i++)
	{
		scanf("%d",&a[i].s);
		a[i].num=i;
	}
	for(int i=1;i<=2*n;i++)
	{
		scanf("%d",&a[i].p);
	}
	sort(a+1,a+2*n+1,cmp);
	for(int i=1;i<=2*n;i++)
	{
		c[i]=a[i];
	}
	while(r--)
	{
		int t1=0,t2=0;
		for(int i=1;i<=2*n;i+=2)
		{
			if(c[i].p>c[i+1].p)	
			{
				c[i].s++;
				win[++t1]=c[i];
				lose[++t2]=c[i+1];
			}
			else 
			{
				c[i+1].s++;
				win[++t1]=c[i+1];
				lose[++t2]=c[i];
			}
		}	
//		for(int i=1;i<=2*n;i++)
//		{
//			cout<<c[i].num<<' '<<c[i].s<<endl;
//		}
//		cout<<win[1].num<<win[2].num<<lose[1].num<<lose[2].num;
		p1=1,p2=1;
		int t=0;
		while(p1<=n&&p2<=n)
		{
			if(win[p1].s!=lose[p2].s)
			{
				if(win[p1].s>lose[p2].s)
				{
					c[++t]=win[p1];
					p1++;
				}
				else
				{
					c[++t]=lose[p2];
					p2++;
				}
			}
			else
			{
				if(win[p1].num<lose[p2].num)
				{
					c[++t]=win[p1];
					p1++;
				}
				else
				{
					c[++t]=lose[p2];
					p2++;
				}	
			}
		}
		if(p1==n+1)
		{
			while(p2<=n)
			{
				c[++t]=lose[p2];
				p2++;
			}
		}
		if(p2==n+1)
		{
			while(p1<=n)
			{
				c[++t]=win[p1];
				p1++;
			}
		}
	} 
	printf("%d",c[q].num);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rem_Inory/article/details/81265302
今日推荐