NOIP2011普及組 瑞士輪(重慶一中高2018級信息學競賽測驗4) 解題報告


做題思路(錯解):拿到這道題時,想法比較簡單,直接枚舉,每進行一輪比賽,將選手的得分更新,並用sort按選手的得分由大到小(得分相同,按編號由小到大)排序,最後直接輸出答案。因爲感覺要超時,所以用了手工輸入,結果最後還是對於大的數據超時了。這種算法的時間複雜度爲O(R*2*N*log2N),很明顯當所有數據取最大值時,會超時。


解題思路(正解):本題的正解是運用分治算法的歸併排序,在輸入後先用sort排序一次,然後,每進行一輪比賽,進行一次歸併排序,歸併排序時,將贏的選手得分加1,並放入win數組(結構體),將輸的選手放入lose數組(結構體),然後就直接將win和lose數組歸併進原數組中,最後輸出答案即可。這種算法的時間複雜度爲O(R*2*N),不會超時。需要注意的是,在歸併排序時,要注意選手得分相同時,將編號小的排在前面。


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=200005;
int N,R,Q;
struct data
{
	int s,w,id;
};
data a[maxn],win[maxn],lose[maxn];
bool cmp(data aa,data bb)
{
	if(aa.s!=bb.s)  return aa.s>bb.s;
	else  return aa.id<bb.id;
}
void _read1(int i)  //手工輸入 
{
	char ch=getchar();
	while(ch<'0' || ch>'9')  ch=getchar();
	int x=0;
	while(ch>='0' && ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	a[i].s=x;
}
void _read2(int i)
{
	char ch=getchar();
	while(ch<'0' || ch>'9')  ch=getchar();
	int x=0;
	while(ch>='0' && ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	a[i].w=x;
}
void merge_sort()  
{
	int i1=1,i2=1;
	for(int i=1;i<2*N;i=i+2)  //計算該輪比賽後選手的得分,並轉存至win和lose數組(結構體)中
	{
		if(a[i].w>a[i+1].w)
		{
			a[i].s++;
			win[i1++]=a[i];
			lose[i2++]=a[i+1];
		}
		if(a[i].w<a[i+1].w)
		{
			a[i+1].s++;
			win[i1++]=a[i+1];
			lose[i2++]=a[i];
		}
	} 
	int i=1,j=1,k=1;  //歸併排序
	while(i<i1 && j<i2)  
	{
		if(cmp(win[i],lose[j]))  //注意判斷得分相同時,編號小的排在前面
		{
			a[k++]=win[i++];
		}
		else
		{
			a[k++]=lose[j++];
		}
	}
	while(i<i1)  a[k++]=win[i++];
	while(j<i2)  a[k++]=lose[j++];
}
int main()
{
	//freopen("swiss.in","r",stdin);
	//freopen("swiss.out","w",stdout);
	scanf("%d%d%d",&N,&R,&Q);
	for(int i=1;i<=2*N;i++)
	{
		_read1(i);
		a[i].id=i;
	}
	for(int i=1;i<=2*N;i++)
	_read2(i);
	sort(a+1,a+1+2*N,cmp);  //按每位選手的總分由大到小排序,總分相同的按編號由小到大排序 
	for(int i=1;i<=R;i++)  //一共進行R輪比賽 
	{
		merge_sort();
	}
	printf("%d\n",a[Q].id);
	return 0;
}


發佈了57 篇原創文章 · 獲贊 8 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章