NOI 3343 NOI3344热血和冷血格斗场

注意先做的热血格斗场,冷血的思路相同。

题目来源

(OPENJUDGE)NOI3343:热血格斗场  http://noi.openjudge.cn/ch0309/3343/

总时间限制: 1000ms 内存限制: 65536kB 


描述

为了迎接08年的奥运会,让大家更加了解各种格斗运动,facer新开了一家热血格斗场。格斗场实行会员制,但是新来的会员不需要交入会费,而只要同一名老会员打一场表演赛,证明自己的实力。

我们假设格斗的实力可以用一个正整数表示,成为实力值。另外,每个人都有一个唯一的id,也是一个正整数。为了使得比赛更好看,每一个新队员都会选择与他实力最为接近的人比赛,即比赛双方的实力值之差的绝对值越小越好,如果有两个人的实力值与他差别相同,则他会选择比他弱的那个(显然,虐人必被虐好)。

不幸的是,Facer一不小心把比赛记录弄丢了,但是他还保留着会员的注册记录。现在请你帮facer恢复比赛纪录,按照时间顺序依次输出每场比赛双方的id。

输入
第一行一个数n(0 < n <=100000),表示格斗场新来的会员数(不包括facer)。以后n行每一行两个数,按照入会的时间给出会员的id和实力值。一开始,facer就算是会员,id为1,实力值1000000000。输入保证两人的实力值不同。

输出
N行,每行两个数,为每场比赛双方的id,新手的id写在前面。
 

思路:建立实力和id的映射map,因为map具有自动排序的特性,所以每次读一个新的选手的实力和id,并insert到map时,会自动排序。然后只要找到当前选手在map中的位置,其前一个元素和后一个元素必然是实力值之差最小的元素。注意边界:即当前选手可能是begin,没有前一个选手,或是end-1,没有后一个选手。

代码如下:rs记录最终的结果,中间的一大堆输入注释是因为我输出发现printf("%ld %ld",id,val),这句话不好使,必须分开写,不然第二个数字总输出0. 

/*
描述

为了迎接08年的奥运会,让大家更加了解各种格斗运动,facer新开了一家热血格斗场。格斗场实行会员制,但是新来的会员不需要交入会费,而只要同一名老会员打一场表演赛,证明自己的实力。

我们假设格斗的实力可以用一个正整数表示,成为实力值。另外,每个人都有一个唯一的id,也是一个正整数。为了使得比赛更好看,每一个新队员都会选择与他实力最为接近的人比赛,即比赛双方的实力值之差的绝对值越小越好,如果有两个人的实力值与他差别相同,则他会选择比他弱的那个(显然,虐人必被虐好)。

不幸的是,Facer一不小心把比赛记录弄丢了,但是他还保留着会员的注册记录。现在请你帮facer恢复比赛纪录,按照时间顺序依次输出每场比赛双方的id。

输入
第一行一个数n(0 < n <=100000),表示格斗场新来的会员数(不包括facer)。以后n行每一行两个数,按照入会的时间给出会员的id和实力值。一开始,facer就算是会员,id为1,实力值1000000000。输入保证两人的实力值不同。

输出
N行,每行两个数,为每场比赛双方的id,新手的id写在前面。
---------------------
使用map,key=实力,value是id,每次加入一个新的选手自动按key排序,使得最接近的就是相邻的两个选手。
*/

#include<iostream>
#include<map>
using namespace std;
typedef long long LL;
int main() {
	map<LL, LL> member;
	member.insert(make_pair(1000000000, 1));
	LL n = 0;
	//cin >> n;
	scanf("%ld", &n);
	//cout << n << endl;
	
	LL* rs = new LL[2 * n];
	for (LL i = 0; i < n; i++) {
		LL id = 0;
		LL val = 0;
		scanf("%ld %ld", &id, &val);
		//scanf("%d", &id);
		//cout << "id id" << id << endl;
		//scanf("%d", &val);
		//cout << "val is " << val << endl;
		//cin >> id;
		//cin>>val;
		//printf("-----%ld ", id);
		//printf("%ld \n", val);
	//	cout << "id id" << id << "  val is " << val << endl;
		rs[2 * i] = id;
		member.insert(make_pair(val, id));
		
		map<LL, LL>::iterator iter = member.find(val);
		if (iter == member.begin()) {
			iter++;
			int p2 = iter->second;
			rs[2 * i + 1] = p2;
			continue;
		}
		iter--;
		int p1 = (iter)->second;
		int s1 = (iter)->first;
		iter++;
		iter++;
		if (iter == member.end()) {
			rs[2 * i + 1] = p1;
			continue;
		}
		int p2 = (iter)->second;;
		int s2= (iter)->first;
		if (abs(val - s1) <= abs(val - s2)) {
			rs[2 * i + 1] = p1;
		}
		else {
			rs[2 * i + 1] = p2;
		}

	}
	for (LL i = 0; i <  n; i++) {
		printf("%ld ", rs[2 * i]);
		printf("%ld \n", rs[2 * i + 1]);
	}
	//system("pause");
	return 0;
	
}

冷血格斗场其实是类似的思想,关键在于如果存在多个与之相同绝对值的,选择id小的那个。

直接在map插入之前进行搜索。如果该实力的选手已经存在,那么不插入,直接和这个选手对阵(因为绝对值之差为0,肯定和这个人打,并且id是最小的(在下两行解释)),

否则插入,执行和热血场一样的操作。

由于输入保证了id的从小到大的次序,所以如果存在这个实力的选手,就不用插入,保证了map中相同实力的选手只有一个,而且总是id最小的

代码如下:

#include<iostream>
#include<map>
using namespace std;
typedef long long LL;
int main() {
	map<LL, LL> member;
	member.insert(make_pair(1000000000, 1));
	LL n = 0;
	//cin >> n;
	scanf("%ld", &n);
	//cout << n << endl;

	LL* rs = new LL[2 * n];
	for (LL i = 0; i < n; i++) {
		LL id = 0;
		LL val = 0;
		scanf("%ld %ld", &id, &val);
		//scanf("%d", &id);
		//cout << "id id" << id << endl;
		//scanf("%d", &val);
		//cout << "val is " << val << endl;
		//cin >> id;
		//cin>>val;
		//printf("-----%ld ", id);
		//printf("%ld \n", val);
		//	cout << "id id" << id << "  val is " << val << endl;
		rs[2 * i] = id;
		map<LL, LL>::iterator iter = member.find(val);
		if (iter == member.end()) {
			member.insert(make_pair(val, id));
			iter = member.find(val);
			if (iter == member.begin()) {
				iter++;
				int p2 = iter->second;
				rs[2 * i + 1] = p2;
				continue;
			}
			iter--;
			int p1 = (iter)->second;
			int s1 = (iter)->first;
			iter++;
			iter++;
			if (iter == member.end()) {
				rs[2 * i + 1] = p1;
				continue;
			}
			int p2 = (iter)->second;;
			int s2 = (iter)->first;
			if (abs(val - s1) <= abs(val - s2)) {
				rs[2 * i + 1] = p1;
			}
			else {
				rs[2 * i + 1] = p2;
			}
		}
		else {
			rs[2 * i + 1] = iter->second;
			continue;
		}
	}
	for (LL i = 0; i < n; i++) {
		printf("%ld ", rs[2 * i]);
		printf("%ld \n", rs[2 * i + 1]);
	}
	//system("pause");
	return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值