P1781 宇宙总统

题目地址:https://www.luogu.com.cn/problem/P1781html

题目描述:地球历公元 6036 年,全宇宙准备竞选一个最贤能的人当总统,共有 n 个非凡拔尖的人竞选总统,如今票数已经统计完毕,请你算出谁可以当上总统。算法

输入格式:第一行为一个整数 n,表明竞选总统的人数。编程

接下来有 n 行,分别为第一个候选人到第 n 个候选人的票数。第一我的的票数是1,日后依次叠加。函数

输出格式:共两行,第一行是一个整数 m,为当上总统的人的号数。第二行是当上总统的人的选票。this

提示:票数可能会很大,可能会到100位数字。全宇宙有这么多人?宇宙总管啊,你确实要实行计划生育的基本策略了,你看人这么多,搞得我还要用高精作这道题!,1<=n<=20。spa

这是一道排序和高精同时使用的题目。通常这种须要对多种元素进行排序的题目(好比说本题的m(号数)和n(票数)),能够考虑用结构体作。因而,我建立了一个表示候选人信息的结构体:指针

struct data
{
    char number[101];//票数 
    int rank;//
    void operator=(data& a)//表示data对于等于号的运算法则 
    {
        strcpy(this->number,a.number);//this表示调用此函数的对象自己,是一个指针 
        this->rank=a.rank; 
    }
}a[21]; 

其中operator=是最须要讲一讲的。code

operator是一种特殊的函数,这种函数的命名是operator后跟一个运算符(中间没有空格)。它只能在一个结构体(或面向对象编程里的“类”)中定义。这种函数是为了明确结构体中运算符的运算法则的。通常的加减乘除等各类运算符,只适用于int等数字类型。若是让一个结构体(如本题的data)使用运算符:htm

int a,b=1;
a=b;//b的值被赋给了a
data c,d;
c=d;//计算机:什么意思?该怎么执行赋值?你告诉我呀!

很明显编译器并不知道怎么执行赋值操做,会报错。对象

那么,只能让咱们告诉编译器了!

上述operator=(data& a)函数表示等号的左右边都是data类型时的操做。还须要介绍一下this指针。它表示使用这个函数的对象自己。举例说明:

struct my_str
{
    int num;
    void output()
    {
        cout<<this->num;
    } 
    void compare(my_str other)
    {
        if(this->num<other.num) cout<<"Smaller"; 
        else if(this->num==other.num) cout<<"Same";
        else cout<<"Bigger";
    } 
};
int main()
{
    my_str a,b;
    a.num=1;
    b.num=2;
    a.output();//a是操纵函数的结构体对象自己,此时output里的this就是a。输出:1 
    b.compare(a);//此时this是b。因为2>1,因此输出:Bigger。 
}

this看起来好像没什么卵用,只是起到让代码意思更清晰而已。可是随着编程的深刻,this指针将会颇有用。

operator函数能够定义各类类型的运算符,不只是通常的加减乘除和赋值,还有关系运算符,逻辑运算符,特殊运算符等等(具备极重要意义的运算符除外,好比说做用域解析运算符::和宏符号#)。值得一提的是,因为等号在通常状况下不返回值,因此它被声明为void函数。同理,逻辑运算符由于要返回真或假值以供if或while使用,因此operator!,operator&&和operator||应声明为返回bool。参数也要注意,关系运算符、赋值运算符、&&和||在通常状况下有两个操做数,因此它们的operator函数应该有且只有一个参数表示右操做数(左操做数通常就是调用函数的对象自己,不用再声明)。

回到原题。个人想法是用选择排序,所以须要比较。然而高精度数字本质上是字符串,字符串没法直接用大于小于等于来比较,因此我写了一个比较高精数的函数:

#define LEFT_IS_BIGGER false//为了便于理解
#define RIGHT_IS_BIGGER true
bool WHO_IS_BIGGER(char* a,char* b)
{
    int lena=strlen(a);
    int lenb=strlen(b);
    if(lena!=lenb)//位数不同,直接肯定谁大谁小
    {
        if(lena>lenb) return LEFT_IS_BIGGER;
        else return RIGHT_IS_BIGGER;
    }
    else
    {
        for(int i=0;i<lena;i++)
        {
            if(a[i]/*-48*/>b[i]/*-48*/) return LEFT_IS_BIGGER;//从高位向低位,若遇到不一样的数字就能够直接判断大小
            else if(a[i]<b[i]) return RIGHT_IS_BIGGER;
            else continue;
        } 
    }
}

为何a[i]后面有个注释的-48?他的目的是将字符的0123456789转换为数字的0123456789(0的ASCII码是48)。但其实不必这样作。能够想到,两个字符的数字比大小和两个转换后的数字比大小返回的结果是同样的。因而我把它注释掉了。

对了,选择排序还须要交换(swap函数),但它只适用于int,因此我写了一个交换data对象的函数:

void my_swap(data& a,data& b)
{
    data temp=a;
    a=b;
    b=temp;
} 

和int的swap同样,只是int所有换成了data而已。这里operator=就派上用场了。这个函数里的等号都调用了operator=函数,很是天然,没有一点编译器错误,咱们不须要再额外定义一个对于data的赋值函数,用现成的等号就行,简明易懂。这就是operator函数的好处。

最后就是主函数了。道理和选择排序的原理同样,若不理解选择排序,能够查阅相关百科或书籍。

int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        scanf("%s",a[i].number);
        a[i].rank=i+1;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            if(WHO_IS_BIGGER(a[i].number,a[j].number)==RIGHT_IS_BIGGER)
            {
                my_swap(a[i],a[j]);
            }
        }
    }
    cout<<a[0].rank<<endl;
    printf("%s",a[0].number);
}
相关文章
相关标签/搜索