天天看點

新手入門刷題(專題二)排序 (第二部分)

新手入門刷題(專題二)排序

4.12

宇宙總統

題目描述

地球曆公元 6036 年,全宇宙準備競選一個最賢能的人當總統,共有 n個非凡拔尖的人競選總統,現在票數已經統計完畢,請你算出誰能夠當上總統。

輸入樣例

5	//參賽人數
98765	//得票數 票數可能會很大,可能會到 100位數字。
12365
87954
1022356
985678
           

輸出樣例

4
1022356
           

思路

本題的票數用string存儲,比較時先比較票長,長度一緻則比較大小。

代碼

#include<iostream>
#include<algorithm>
using namespace std;
int n;
struct Candidate {
    int num;//序号
    string grade;//票數
} pre[25];
//自定義比較函數
bool cmp(Candidate a,Candidate b){
    if(a.grade.length()>b.grade.length()) return a.grade.length()>b.grade.length();
    else if(a.grade.length()==b.grade.length()) return a.grade>b.grade;
    return false;
}
int main() {
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>pre[i].grade;
        pre[i].num = i;
    }
    sort(pre+1,pre+n+1,cmp);
    cout<<pre[1].num<<endl<<pre[1].grade;
    return 0;
}
           

[USACO07DEC]Bookshelf B

題目描述

略,求最少幾個奶牛即可到書架高度

輸入樣例

6 40	//奶牛數為6,書架高為40
6	//第一個奶牛高度
18
11
13
19
11
           

輸出樣例

3
           

思路

先快排所有奶牛高度,再從大到小相加,直到>=書架高度,統計相加的奶牛個數

代碼

#include <iostream>
#include<algorithm>
using namespace std;
int n,b,h[20020],t,k;
//快排模闆要記住
int qs(int q[],int l,int r){
    if(l>=r) return q[l];
    int i = l-1,j = r+1, x = q[l+r>>1];
    while(i<j){
        do i++;while(q[i]<x);
        do j--;while(q[j]>x);
        if(i<j) swap(q[i],q[j]);
    }
    qs(q, l, j);
    qs(q, j + 1, r);
}
int main() {
    cin>>n>>b;
    for(int i=0;i<n;i++) cin>>h[i];
    qs(h,0,n-1);
    while(t<b&&k<n){
        t += h[n-1-k];
        k++;
    }
    cout<<k;
    return 0;
}
           

車廂重組

題目描述

好家夥,考查冒泡可還行。

代碼

#include <iostream>
#include<algorithm>
using namespace std;
int n,t[10010],times;
int main() {
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&t[i]);
    }
    for(int i=0;i<n-1;i++){
        for(int j=i+1;j<n;j++){
            if(t[i]>t[j]) {
                swap(t[i],t[j]);
                times++;
            }
        }
    }
    printf("%d",times);
    return 0;
}
           

歡樂的跳

題目描述

一個包含n個元素的整數數組,如果數組兩個連續元素之間差的絕對值包括了[1,n-1]之間的所有整數,則稱之符合“歡樂的跳”,如數組 {1,4,2,3} 符合“歡樂的跳”,因為差的絕對值分别為:3,2,1。

給定一個數組,你的任務是判斷該數組是否符合“歡樂的跳”。

輸入樣例

5 1 4 2 -1 6	//第一個數字代表數組長度,之後代表每一個數字
           

輸出樣例

jolly	//符合“歡樂的跳”輸出
Not jolly	//不符合“歡樂的跳”輸出
           

思路

數組長度 n ( 1 ≤ n ≤ 1000 )

數組中的數字範圍 [-100000000,100000000]

本題提供兩種解法

第一種用桶裝兩數之差,即采用數組下标的方式存儲兩數之差,不過數組的長度要大于100000000。

隻需要數組範圍 [1,n-1] 之内的數全是 1 即符合“歡樂的跳”,具體見代碼一。

第二種方法,我們可以研究一下題目,顯然在存數組的過程中即可計算兩數之差,一旦兩數之差出現重複,一定不符合“歡樂的跳”,具體見代碼二。

代碼一

#include <iostream>
#include<algorithm>
using namespace std;
int n,t[1010],num[200000000];
int main() {
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&t[i]);
    }
    //桶
    for(int i=0;i<n-1;i++){
        int tmp;
        tmp = t[i]>=t[i+1]?t[i]-t[i+1]:t[i+1]-t[i];
        num[tmp]++;
    }
    for(int i=1;i<n;i++){
        if(num[i]==0){
            printf("Not jolly");
            return 0;
        }
    }
    printf("Jolly");
    return 0;
}
           

代碼二

#include <iostream>
using namespace std;
int n,a,b,c;
bool d[1010];
int main() {
    //輸入數組長度
    scanf("%d",&n);
    //輸入第一個數
    scanf("%d",&a);
    //從第二個數開始輸入
    for(int i=1;i<n;i++){
        scanf("%d",&b);
        //計算兩數之差
        c = a>=b?a-b:b-a;
        //兩數之差不在[1,n-1]之内,必定不符合
        if(c>=1&&c<=n-1){
            //判斷是否重複,重複也必定不符合
            if(d[c]) {
                printf("Not jolly");
                return 0;
            }
            //不重複,則繼續
            else d[c] = true;
        }else {
            printf("Not jolly");
            return 0;
        }
        //指派第二個數給第一個數,開啟下輪循環
        a = b;
    }
    //能夠完成輸入循環,則必定符合
    printf("Jolly");
    return 0;
}
           

4.13

[NOIP2009 普及組] 分數線劃定

題目描述

世博會志願者的選拔工作正在 A 市如火如荼的進行。為了選拔最合适的人才,A市對所有報名的選手進行了筆試,筆試分數達到面試分數線的選手方可進入面試。面試分數線根據計劃錄取人數的 150% 劃定,即如果計劃錄取m名志願者,則面試分數線為排名第 m×150%(向下取整)名的選手的分數,而最終進入面試的選手為筆試成績不低于面試分數線的所有選手。

現在就請你編寫程式劃定面試分數線,并輸出所有進入面試的選手的報名号和筆試成績。

輸入樣例

6 3 //報名參加筆試的選手總數 計劃錄取的志願者人數
1000 90 //選手的報名号 選手的筆試成績
3239 88 
2390 95 
7231 84 
1005 95 
1001 88
           

輸出樣例

88 5 
1005 95 
2390 95 
1000 90 
1001 88 
3239 88 
//按照筆試成績從高到低輸出,如果成績相同,則按報名号由小到大的順序輸出。
           

說明/提示

【樣例說明】

m×150%=3×150%=4.5,向下取整後為4。保證4個人進入面試的分數線為88,但因為88有重分,是以所有成績大于等于88 的選手都可以進入面試,故最終有5個人進入面試。

思路

學習新排序啦, 歸并排序, 時間複雜度nlogn, 穩定!!!

快排時間複雜度為nlogn, 但是不穩定, 本題如果成績相同時按輸入先後順序輸出, 則使用快排不合适, 因為不穩定會導緻成績相同但是輸出順序與輸入順序不一緻.

但是本題要求根據 成績從大到小 和 成績相同則根據編号從小到大輸出, 是以使用 快排 和 歸并排序 皆可

歸并排序模闆

const int N=1e6+10;
int q[N],temp[N];
void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;
    int mid = (l + r) >> 1;
    merge_sort(q, l, mid);
    merge_sort(q, mid + 1, r);
    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        //正序
        if (q[i] <= q[j]) tmp[k++] = q[i++];
    	//逆序	
   	    //if (q[i] >= q[j]) tmp[k++] = q[i++];
        else tmp[k++] = q[j++];
    while (i <= mid) tmp[k++] = q[i++];
    while (j <= r) tmp[k++] = q[j++];
    for (int i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
}
           

采用歸并排序解題代碼

#include<iostream>
using namespace std;
struct Emp{
    int num;
    int grade;
}emp[5050],tmp[5050];
int n,m;
//根據歸并排序模闆修改,穩定
void merge_sort(int l, int r)
{
    if (l >= r) return;
    int mid = (l + r) >> 1;
    merge_sort(l, mid);
    merge_sort(mid + 1, r);
    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        //成績從大到小
        if (emp[i].grade > emp[j].grade) tmp[k++] = emp[i++];
    	//成績相同,編号從小到大
        else if (emp[i].grade == emp[j].grade && emp[i].num <= emp[j].num) tmp[k++] = emp[i++];
        else tmp[k++] = emp[j++];
    while (i <= mid) tmp[k++] = emp[i++];
    while (j <= r) tmp[k++] = emp[j++];
    for (int i = l, j = 0; i <= r; i++, j++) emp[i] = tmp[j];
}
int main(){
    scanf("%d%d",&n,&m);
    m = m * 1.5;
    for(int i=1;i<=n;i++) scanf("%d%d",&emp[i].num,&emp[i].grade);
    merge_sort(1,n);
    //成績相同時接着往下找
    while(emp[m].grade==emp[++m].grade);
    printf("%d %d\n",emp[m].grade,--m);
    for(int i=1;i<=m;i++) printf("%d %d\n",emp[i].num,emp[i].grade);
    return 0;
}
           

采用快排解題代碼

#include<iostream>
using namespace std;
struct Emp{
    int num;
    int grade;
}emp[5050];
int n,m;
//改寫快排
void qs(int l,int r){
    if(l>=r) return;
    int i = l-1, j = r+1, x = emp[(r+l)>>1].grade, y = emp[(r+l)>>1].num;
    while(i<j){
        //成績從大到小 成績相同,編号從小到大
        do i++;while(emp[i].grade>x||(emp[i].grade==x&&emp[i].num<y));
        do j--;while(emp[j].grade<x||(emp[j].grade==x&&emp[j].num>y));
        if(i<j) swap(emp[i],emp[j]);
    }
    qs(l,j);
    qs(j+1,r);
}
int main(){
    scanf("%d%d",&n,&m);
    m = m * 1.5;
    for(int i=1;i<=n;i++) scanf("%d%d",&emp[i].num,&emp[i].grade);
    qs(1,n);
    //成績相同時接着往下找
    while(emp[m].grade==emp[++m].grade);
    printf("%d %d\n",emp[m].grade,--m);
    for(int i=1;i<=m;i++) printf("%d %d\n",emp[i].num,emp[i].grade);
    return 0;
}
           

攀爬者

題目描述

HKE考完GDOI之後跟他的神犇小夥伴們一起去爬山。

他在地形圖上标記了N個點,每個點Pi都有一個坐标(xi,yi,zi)。所有點對中,高度值z不會相等。HKE準備從最低的點爬到最高的點,他的攀爬滿足以下條件:

(1) 經過他标記的每一個點;

(2) 從第二個點開始,他經過的每一個點高度z都比上一個點高;

(3) HKE會飛,他從一個點Pi爬到Pj的距離為兩個點的歐幾裡得距離。即,

( X i − X j ) 2 + ( Y i − Y j ) 2 + ( Z i − Z j ) 2 \sqrt{(X_i-X_j)^2+(Y_i-Y_j)^2+(Z_i-Z_j)^2} (Xi​−Xj​)2+(Yi​−Yj​)2+(Zi​−Zj​)2

現在,HKE希望你能求出他攀爬的總距離。

輸入樣例

5	//點的個數
2 2 2	//x y z
1 1 1
4 4 4
3 3 3
5 5 5
           

輸出樣例

6.928
           

說明/提示

【樣例說明】

對于100%的資料,1≤N≤50000,答案的範圍在double範圍内。

思路

先按照z軸排序, 再計算兩點距離.

代碼

#include<iostream>
#include<math.h>
#include<cmath>
#include<algorithm>
using namespace std;
double ans;
struct Node { 
    int x,y,z; 
    //重載<
    bool operator < (const Node &b)const{
		return z<b.z;
	}
} a[50050];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    sort(a,a+n);
    for(int i=1;i<n;i++) ans+=sqrt(pow(a[i].x-a[i-1].x,2)+pow(a[i].y-a[i-1].y,2)+pow(a[i].z-a[i-1].z,2));
    printf("%.3lf",ans);
    return 0;
}
           

4.14

生日

題目描述

cjf

君想調查學校 OI 組每個同學的生日,并按照年齡從大到小的順序排序,如果有兩個同學生日相同,輸入靠後的同學先輸出。但

cjf

君最近作業很多,沒有時間,是以請你幫她排序。

輸入樣例

3	//人數
Yangchu 1992 4 23	//姓名 生日
Qiujingya 1993 10 13
Luowen 1991 8 1
           

輸出樣例

Luowen	//姓名
Yangchu
Qiujingya
           

說明/提示

資料規模

1<n<100

length(s)<20

思路

結構體加sort函數,本題和上一題基本一樣。

代碼

#include<iostream>
#include<algorithm>
using namespace std;
struct Students { 
    int nu;
    char na[25];
    int ye;
    int mo;
    int da;
    //sort預設從小到大排序,我們需要重載 < 運算符号
    //重載<
    bool operator < (const Students &b)const{
        if(ye<b.ye) return ye<b.ye;
        else if(ye==b.ye&&mo<b.mo) return mo<b.mo;
        else if(ye==b.ye&&mo==b.mo&&da<b.da) return da<b.da;
        else if(ye==b.ye&&mo==b.mo&&da==b.da&&nu>b.nu) return nu>b.nu;
        return false;
	}
} a[110];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        a[i].nu = i;
        //提供兩種輸入方法
        //小知識,字元串名稱本身就是位址,無需添加位址符
        // scanf("%s %d %d %d",a[i].na,&a[i].ye,&a[i].mo,&a[i].da);
        cin>>a[i].na>>a[i].ye>>a[i].mo>>a[i].da;
    } 
    sort(a,a+n);
    for(int i=0;i<n;i++) printf("%s\n",a[i].na);
    return 0;
}
           

[NOIP1998 提高組] 拼數

題目描述

設有 n個正整數 a1…an,将它們聯接成一排,相鄰數字首尾相接,組成一個最大的整數。

輸入樣例

4
7 13 4 246
           

輸出樣例

7424613
           

說明/提示

對于全部的測試點,保證

1 ≤ n ≤ 20 1≤n≤20 1≤n≤20

1 ≤ a i ≤ 1 0 9 1≤ai≤10^9 1≤ai≤109

思路

隻需要判段兩數先後相加的大小即可。

代碼

#include<iostream>
#include<algorithm>
using namespace std;
string s[25];
//
bool cmp(string a,string b){
    return a+b>b+a;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++) cin>>s[i];
    sort(s,s+n,cmp);
    for(int i=0;i<n;i++) cout<<s[i];
    return 0;
}