归并排序 习题

P1309 瑞士轮

    • 4.4K通过
    • 17.9K提交
  • 题目提供者CCF_NOI
  • 评测方式云端评测
  • 标签NOIp普及组2011高性能
  • 难度普及/提高-
  • 时空限制1000ms / 128MB

 提交  题解   

提示:收藏到任务计划后,可在首页查看。

最新讨论显示

推荐的相关题目显示

题目背景

在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。

本题中介绍的瑞士轮赛制,因最早使用于 18951895 年在瑞士举办的国际象棋比赛而得名。它可以看作是淘汰赛与循环赛的折中,既保证了比赛的稳定性,又能使赛程不至于过长。

题目描述

2 \times N2×N 名编号为 1-2N12N 的选手共进行R 轮比赛。每轮比赛开始前,以及所有比赛结束后,都会按照总分从高到低对选手进行一次排名。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。

每轮比赛的对阵安排与该轮比赛开始前的排名有关:第 11 名和第 22 名、第 33 名和第 44 名、……、第 2K - 12K1 名和第 2K2K 名、…… 、第 2N - 12N1 名和第 2N2N 名,各进行一场比赛。每场比赛胜者得 11 分,负者得 00 分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。

现给定每个选手的初始分数及其实力值,试计算在R 轮比赛过后,排名第 QQ 的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。

输入输出格式

输入格式:

第一行是三个正整数 N,R ,QN,R,Q ,每两个数之间用一个空格隔开,表示有 2 \times N2×N 名选手、 RR 轮比赛,以及我们关心的名次 QQ 。

第二行是 2 \times N2×N 个非负整数 s_1, s_2, …, s_{2N}s1,s2,,s2N ,每两个数之间用一个空格隔开,其中 s_isi 表示编号为 ii 的选手的初始分数。 第三行是 2 \times N2×N 个正整数 w_1 , w_2 , …, w_{2N}w1,w2,,w2N ,每两个数之间用一个空格隔开,其中 w_iwi 表示编号为 ii的选手的实力值。

输出格式:

一个整数,即 RR 轮比赛结束后,排名第 QQ 的选手的编号。

输入输出样例

输入样例#1:  复制
2 4 2 
7 6 6 7 
10 5 20 15 
输出样例#1:  复制
1

说明

【样例解释】

【数据范围】

对于 30\%30% 的数据, 1 ≤ N ≤ 1001N100 ;

对于 50\%50% 的数据, 1 ≤ N ≤ 10,0001N10,000 ;

对于 100\%100% 的数据, 1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s_1, s_2, …, s_{2N}≤10^8,1 ≤w_1, w_2 , …, w_{2N}≤ 10^81N100,000,1R50,1Q2N,0s1,s2,,s2N108,1w1,w2,,w2N108



这题由于是每次两个人进行比较,所以用归并算法比较合适

设置一个结构体,

typedef struct node {
	int num;//编号
	int score;//分数
	int w;//实力值
}Node;
然后开辟三个数组:
Node win[100003];//用来储存比赛赢的人
Node lose[100003];//输的
Node p[200005];//总的数组

这是归并:

void merge()
{
	int i = 1;//用i来指向win数组
	int j = 1;//用j来指向lose数组
	int k = 1;//指向p数组
	while (i <= n && j <= n)
	{
		if (win[i].score > lose[j].score)//如果win数组的头元素大于lose的头元素,那么就把win头元素插入到p数组
		{
			p[k] = win[i++];
		}
		else if (win[i].score == lose[j].score)
		{
			if (win[i].num < lose[j].num)
			{
				p[k] = win[i++];
			}
			else
			{
				p[k] = lose[j++];
			}
		}
		else
		{
			p[k] = lose[j++];
		}
		k++;
	}
	while (i <= n)//因为可能会提前把一个数组插完,那么就会有剩下的
	{
		p[k++] = win[i++];
	}
	while (j <= n)
	{
		p[k++] = lose[j++];
	}
}

这是两个队进行比赛的方法
void sdf()
{
	int s = 1;
	int m = 1;
	for (int i = 1; i <= n; i++)
	{
		if (p[s].w > p[s + 1].w)
		{
			p[s].score++;
			win[m] = p[s];//把获胜的元素插入到win数组
			lose[m] = p[s + 1];//把输的元素插入到lose数组
		}
		else if (p[s].w < p[s + 1].w)
		{
			p[s + 1].score++;
			win[m] = p[s+1];
			lose[m] = p[s];
		}
		s += 2;
		m++;
	}
}

总代码奉上:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef struct node {
	int num;//编号
	int score;//分数
	int w;//实力值
}Node;
Node win[100003];
Node lose[100003];
Node p[200005];
int n, r, q;
bool cmp(struct node x,struct node y)
{
	if (x.score > y.score)
		return 1;
	else if (x.score == y.score)
	{
		return x.num < y.num;
	}
	else
	{
		return 0;
	}
}
void merge()
{
	int i = 1;
	int j = 1;
	int k = 1;
	while (i <= n && j <= n)
	{
		if (win[i].score > lose[j].score)
		{
			p[k] = win[i++];
		}
		else if (win[i].score == lose[j].score)
		{
			if (win[i].num < lose[j].num)
			{
				p[k] = win[i++];
			}
			else
			{
				p[k] = lose[j++];
			}
		}
		else
		{
			p[k] = lose[j++];
		}
		k++;
	}
	while (i <= n)
	{
		p[k++] = win[i++];
	}
	while (j <= n)
	{
		p[k++] = lose[j++];
	}
}
void sdf()
{
	int s = 1;
	int m = 1;
	for (int i = 1; i <= n; i++)
	{
		if (p[s].w > p[s + 1].w)
		{
			p[s].score++;
			win[m] = p[s];
			lose[m] = p[s + 1];
		}
		else if (p[s].w < p[s + 1].w)
		{
			p[s + 1].score++;
			win[m] = p[s+1];
			lose[m] = p[s];
		}
		s += 2;
		m++;
	}
}
int main()
{
	cin >> n >> r >> q;
	for (int i = 1; i <= n * 2; i++)
	{
		cin >> p[i].score;
		p[i].num = i;
	}
	for (int i = 1; i <= 2 * n; i++)
	{
		cin >> p[i].w;
	}
	sort(p + 1, p + 2 * n + 1,cmp);
	sdf();
	while (r>0)
	{
		merge();
		sdf();
		r--;
	}
	cout << p[q].num;
	system("pause");
	return 0;
}



猜你喜欢

转载自blog.csdn.net/scwmason/article/details/80933704