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);
}
相關文章
相關標籤/搜索