注意先做的热血格斗场,冷血的思路相同。
题目来源
(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;
}