c++初级代码(1.不知道多少了)冷血格斗场

mooc程序设计(三)第九周第三题

重复是麻烦的一点,
emm这道题emm一开始本着面向对象的思想想要用set来按实力值和id来保存用户的信息,而且想要保存所有的用户信息,所以写了个这样的代码:

#include<set>
#include<iostream>
#include<algorithm>
using namespace std;
class Fighter
{
public:
    int id;
    int point;
    Fighter (int a,int b):id(a),point(b){}



};
class lessthan//我们一般用函数对象传入模板作为类型参数,同时在运算符或者比较的使用的时候,最好尽量少些,防止语义重复,
//比如运算符重载和自己写的比较函数容易弄混,同时也应当注意stl中这些容器传入的标准参数中那些比较函数的参数,比如这里的lessthan
//本来默认调用less,但是我们没有重载运算符,所以不如自己写一个函数对象。
{
public:
    bool operator() (const Fighter A,const Fighter  Ano)
    {
        if(A.point < Ano.point) return true;
        else if(A.point==Ano.point&&A.id<Ano.id)
            return true;
        else
            return false;
    }

};
class equivalent//为了find_if而准备
{
public:
    int point;
    bool operator ()(Fighter A)
    {
        return A.point==point;
    }
    equivalent(Fighter A)
    {

        point=A.point;
    }
};
//要把程序逻辑想清楚,这道题有重复之后问题比较复杂,遇到两个重复的值是难点
int main(void)
{
    int n;
    int id,point;
    multiset<Fighter,lessthan> all;
    typedef Fighter F;
    all.insert(F(1,1000000000));
    multiset<Fighter,lessthan>::iterator low,up,ifeq;
//用文件比较调试;



    cin>>n;
    while(n--)
    {
        cin>>id>>point;

        F f(id,point);//之所以创建了一个fighter对象就是因为自己写的比较函数仅限于fighter之间,所以在比较和后续函数中传递的value
        //都应当是fighter类型的值,
        ifeq=find_if(all.begin(),all.end(),equivalent(f));
        if(ifeq==all.end())//没有重复的该值
        {
            low=all.lower_bound(f);
            if(low!=all.begin()) low--;
            low=find_if(all.begin(),all.end(),equivalent(F(0,low->point)));//这里要注意如果差值绝对值相等,但是小的有许多相等值需要重新定位一个最小的lowerbound
            up=all.upper_bound(f);
            if(up==all.end()) up--;//up恰好是id比较小的那个
        }
        else //有重复的值,这里注意 ,lowerbound 和upperbound 并不能满足要求,如果有重复的要选id最小的,但是lowerbound返回的反而是比较大的那个
        {
            up=low=find_if(all.begin(),all.end(),equivalent(f));
        }
        if((point-low->point) !=(up->point-point))
        {
            cout<<id<<" "<<((point-low->point) <(up->point-point)?low->id:up->id)<<endl;

        }
        else
       {
                cout<<id<<" "<< (up->id>low->id?low->id:up->id) <<endl;
                //从low开始有小于等于point的一直到up之前
       }
        all.insert(f);
    }
    return 0;
}

一开始灰常天真地以为只需要区别和point值有没有重复就可以了,后来发现了一个一直漏掉的问题:如果有实力值相差绝对值相同的两个人我们可以比较这两个人的id,可是问题是,在这里low的那个可能不是唯一一个实力值与新手差值等于up那个的,up本身在set中的顺序就保证了up就是id最小且实力恰好大的那个,但low就不一定了,可能有id小于low的且实力等于low的,所以要再找一下,,,,,
但是修了这个bug之后,特么时间超出限制,果然要ac就必须选择性丢失用户信息,,,,
那么问题能够稍微简单一点:我们用map存用户信息,实力在前,id在后,每次新用户判断其实力值是不是有重复的,如果有那么把id较小的插进去,(也就是说老用户拜拜喽)
emmm,然后过了,,,,,,

#include<iostream>
#include<map>
#include<utility>

using namespace std;

//map中比较显著的特点就是一一映射,同时我们的排序最好都基于key的值来完成,当然综合上对value的比较也可以
//在用stl之前,建议去查一下函数和方法的源码,这里总是吃不看源码的亏,,,于是人为写了好多运算符重载,整个人都不好了,,,
//真的让人难受,这道题做了好多次,,,
int main(void)//不如还是仅存不重复的用户数据,每次如果有重复的
{
    int id,point;
    int n;
    map<int,int> all;
    pair<int,int> _n(1000000000,1);
    all.insert(_n);
    pair<int,int> one;
    map<int,int>::iterator ifeq,low,up;
    cin>>n;
    while(n--)
    {
        cin>>id>>point;
        one.first=point,one.second=id;
        ifeq=all.find(one.first);//这里用algorithm的find会出错,因为algorithm的find中是用==号来寻找对应的值的。
        if(ifeq==all.end())//不存在有相同poin0t值的老用户
        {
            low=all.lower_bound(one.first);
            if(low!=all.begin()) low--;
            up=all.upper_bound(one.first);
            if((one.first-low->first)!=(up->first-one.first))
            {
                cout<<one.second<<" "<<((one.first-low->first)<(up->first-one.first)?low->second:up->second)<<endl;
            }
            else cout<<one.second<<" "<<(low->second < up->second?low->second:up->second)<<endl;
            all.insert(one);
        }
        else
        {
            cout<<one.second<<" "<<ifeq->second<<endl;//直接输出,并且把id较小的那个存到map里
            ifeq->second = (ifeq->second < one.second ? ifeq->second:one.second);
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值