001:冷血格斗场
http://cxsjsxmooc.openjudge.cn/2020t1sprint13/001/
描述
为了迎接08年的奥运会,让大家更加了解各种格斗运动,facer新开了一家冷血格斗场。格斗场实行会员制,但是新来的会员不需要交入会费,而只要同一名老会员打一场表演赛,证明自己的实力。
我们假设格斗的实力可以用一个正整数表示,成为实力值,两人的实力值可以相同。另外,每个人都有一个唯一的id,也是一个正整数。为了使得比赛更好看,每一个新队员都会选择与他实力最为接近的人比赛,即比赛双方的实力值之差的绝对值越小越好,如果有多个人的实力值与他差别相同,则他会选择id最小的那个。
不幸的是,Facer一不小心把比赛记录弄丢了,但是他还保留着会员的注册记录。现在请你帮facer恢复比赛纪录,按照时间顺序依次输出每场比赛双方的id。
输入
第一行一个数n(0 < n <=100000),表示格斗场新来的会员数(不包括facer)。以后n行每一行两个数,按照入会的时间给出会员的id和实力值。一开始,facer就算是会员,id为1,实力值1000000000。
输出
N行,每行两个数,为每场比赛双方的id,新手的id写在前面。
样例输入
3
2 3
3 1
4 2
样例输出
2 1
3 2
4 2
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
typedef multimap<long long, long long> MP;
MP fighters;
//选择强一点的对手时,需要向后在同等实力的对手里选择最小的id选手
long long back(MP::iterator p, int i) {
MP::iterator minp = p;
long long force = minp->first;
long long min_id = minp->second;
for (; p->first == force && p != fighters.end(); ++p) {
if (p->second < min_id) {
minp = p;
min_id = p->second;
}
}
return min_id;
}
//选择差一点的对手时,需要向前在同等实力的对手里选择最小的id选手
long long front(MP::iterator p, int i) {
--p;
MP::iterator minp = p;
long long force = minp->first;
long long min_id = minp->second;
for (; p->first == force && p != fighters.begin(); --p) {
if (p->second < min_id) {
minp = p;
min_id = p->second;
}
}
if (p->first == force) { // 如果上面循环是因为 p == fighters.begin() 而终止,则p指向的元素还要处理
if (p->second < min_id) {
minp = p;
min_id = p->second;
}
}
return min_id;
}
int main() {
int n;
cin >> n;
fighters.insert(make_pair(1000000000, 1)); //插入Facer的资料
long long id, f;
MP::iterator p;
for (int i = 0; i < n; ++i) {
scanf("%lld%lld", &id, &f ); //录入新选手的id和实力值f
p = fighters.lower_bound(f);
long long a, b = 0;
a = p->first;
if (p != fighters.begin()) { //如果p = fighters.begin()时,则--p会出错
b = (--p)->first; ++p;
}
if(fighters.size()==1) //输出第一场格斗的对阵序列时 ,此时容器的size==1,所以对手必定是id=1的Facer
printf("%lld %d\n", id, 1);
else if (p == fighters.begin() || a - f < f - b) //a. 没有更弱的格斗者时,lower_bound()必返回begin() 或 b. 与强点的实力差小时,选更厉害的
printf("%lld %lld\n", id, back(p, i));
else if (p == fighters.end()) //c. 没有更厉害的格斗者时,lower_bound()返回end()
printf("%lld %lld\n", id, (--p)->second);
else if (a - f > f - b) //d. 与差一点的实力差较小时,选择差点的格斗者
printf("%lld %lld\n", id, front(p, i));
else if (a - f == f - b) { // 前后相差绝对值相等时,需要分别查找最小的id
MP::iterator tmp = p;
long long min_id1 = front(tmp, i);
long long min_id2 = back(tmp, i);
if (min_id1 < min_id2)
printf("%lld %lld\n", id, min_id1);
else
printf("%lld %lld\n", id, min_id2);
}
fighters.insert(make_pair(f, id)); //插入新选手的资料
}
return 0;
}
我的代码写的很一般,参考别人的代码之后,感觉相形见绌,故粘贴过来,方便以后参考。
代码的优点在于:
- 保证容器里某一个武力值对应的id始终对应最小值,省去了重复武力值的情况下,最小id的查找过程。
- 应用 [ ]关键字的方法插入数据,而不是用insert的方式,使得代码看起来更加简洁
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
map<int, int> f2id;
int main()
{
int n;
cin >> n;
f2id[1000000000] = 1;
int id, f;
map<int, int>::iterator ite, itep, itel;
while (n--)
{
cin >> id >> f;
if (f2id.find(f) != f2id.end())
{
cout << id << " " << f2id.find(f)->second << endl;
f2id[f] = min(id, f2id.find(f)->second);
continue;
}
ite = f2id.lower_bound(f);
if (ite == f2id.begin())
cout << id << " " << ite->second << endl;
else if (ite == f2id.end())
{
ite--;
cout << id << " " << ite->second << endl;
}
else
{
int pid, pf;
int lid, lf;
ite--;
pid = ite->second;
pf = ite->first;
ite++;
lid = ite->second;
lf = ite->first;
if (lf - f == f - pf)
cout << id << " " << min(pid, lid) << endl;
else if (lf - f > f - pf)
cout << id << " " << pid << endl;
else
cout << id << " " << lid << endl;
}
f2id[f] = id;
}
return 0;
}