2013年北京大学夏令营及保研考试 -B题 冷血格斗场(待解决)

2013年北京大学夏令营及保研考试 -B题


(OPENJUDGE)NOI3344:冷血格斗场 http://noi.openjudge.cn/ch0309/3344/


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


描述

为了迎接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;
}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值