2013年北京大学夏令营及保研考试 -B题
(OPENJUDGE)NOI3344:冷血格斗场 http://noi.openjudge.cn/ch0309/3344/
总时间限制: 1000ms 内存限制: 65536kB
我们假设格斗的实力可以用一个正整数表示,成为实力值,两人的实力值可以相同。另外,每个人都有一个唯一的id,也是一个正整数。为了使得比赛更好看,每一个新队员都会选择与他实力最为接近的人比赛,即比赛双方的实力值之差的绝对值越小越好,如果有多个人的实力值与他差别相同,则他会选择id最小的那个。
不幸的是,Facer一不小心把比赛记录弄丢了,但是他还保留着会员的注册记录。现在请你帮facer恢复比赛纪录,按照时间顺序依次输出每场比赛双方的id。
输入
第一行一个数n(0 < n <=100000),表示格斗场新来的会员数(不包括facer)。以后n行每一行两个数,按照入会的时间给出会员的id和实力值。一开始,facer就算是会员,id为1,实力值1000000000。输入保证两人的实力值不同。
输出
N行,每行两个数,为每场比赛双方的id,新手的id写在前面。
样例输入
描述
为了迎接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
解题思路
使用map实现从实力值到id的映射,以下代码的问题是并没有AC,但测试数据却通过,百思不得其解;
代码
#include <iostream>
#include <map>
using namespace std;
int main() {
map<long long,int>mp;//实力值到id的映射
map<long long,int>::iterator it,it1,it2;
int n;
mp[1000000000]=1;
cin>>n;
int id,cap;//id和实力值
for(int i=0;i<n;i++){
cin>>id>>cap;
mp[cap]=id;
/*for(it=mp.begin();it!=mp.end();it++){
if(it->first == cap){
break;
}
}*/
it=mp.find(cap);//find()是根据key查找value
it1=it2=it;
if(it==mp.begin()){
it1++;
cout<<id<<" "<<it1->second<<endl;
//如果新加会员在map首部,下一个即为挑战者
continue;
}
else{
//map中it的前一个会员
it1--;
int cap1=it1->first;
int id1=it1->second;
//map中it的后一个会员
it2++;
int cap2=it2->first;
int id2=it2->second;
if(abs(cap-cap1)<abs(cap2-cap)){
cout<<id<<" "<<id1<<endl;
//如果有两个人的实力值与他差别相同,实力弱的为下一个挑战者
}
else if(abs(cap-cap1)>abs(cap2-cap)){
cout<<id<<" "<<id2<<endl;
}
else if(abs(cap-cap1)==abs(cap2-cap)){
cout<<id<<" "<<min(id1,id2)<<endl;
}
}
}
return 0;
}
下面代码转载自
http://blog.csdn.net/ArkhamOrginal/article/details/51968551,经测试确实AC
#include <iostream>
#include<map>
using namespace std;
map<int,int>mp; //运用映射建立存储结构
map<int,int>::iterator it;
int n;
int main()
{
mp[1000000000]=1;//首先是facer,编号为1,能力值为1000000000
//freopen("in.txt","r",stdin);
cin>>n;
for(int i=1;i<=n;i++)
{
int id,cap;
scanf("%d%d",&id,&cap);
it=mp.lower_bound(cap);//查找能力值不小于目前即将加入的新成员的元素
if(it==mp.end()) it--;
//迭代器指向映射的最后一个元素后面的地址,说明没有找到,没有人的实力强新人的能力,那么就找到最后一个元素,他的能力值一定是最接近新人的
int t=abs(it->first-cap);
int idx=it->second;
if(it!=mp.begin())//先判断,如果it就指向映射的第一个元素就不执行,否则会访问违规地址
{
it--;
if(t>abs(it->first-cap) || (t==abs(it->first-cap) && it->second<idx))//能力差值相同,去找id小的
{
t=abs(it->first-cap);
idx=it->second;
}
}
printf("%d %d\n",id,idx);
it=mp.find(cap);
if(it->second>id || it==mp.end())
mp[cap]=id;
//因为在加入新成员时,与任意成员进行比赛时都要选择id号最小的,那么一旦在相同的能力值上有了一个人且其id较小的老成员,id较大的新成员就一定不会再进行比赛(优先选择id小的)
}
return 0;
}