數據結構---排序

排序


排序的知識點整理:可以看這位大神的白話經典算法系列中的排序

以下只有解題思路。

魔法優惠券   (25分)

在火星上有個魔法商店,提供魔法優惠券。每個優惠劵上印有一個整數面值K,表示若你在購買某商品時使用這張優惠劵,可以得到K倍該商品價值的回報!該商店還免費贈送一些有價值的商品,但是如果你在領取免費贈品的時候使用面值爲正的優惠劵,則必須倒貼給商店K倍該商品價值的金額…… 但是不要緊,還有面值爲負的優惠劵可以用!(真是神奇的火星)

例如,給定一組優惠劵,面值分別爲1、2、4、-1;對應一組商品,價值爲火星幣M$7、6、-2、-3,其中負的價值表示該商品是免費贈品。我們可以將優惠劵3用在商品1上,得到M$28的回報;優惠劵2用在商品2上,得到M$12的回報;優惠劵4用在商品4上,得到M$3的回報。但是如果一不小心把優惠劵3用在商品4上,你必須倒貼給商店M$12。同樣,當你一不小心把優惠劵4用在商品1上,你必須倒貼給商店M$7。

規定每張優惠券和每件商品都只能最多被使用一次,求你可以得到的最大回報。

輸入格式:

輸入有兩行。第一行首先給出優惠劵的個數N,隨後給出N個優惠劵的整數面值。第二行首先給出商品的個數M,隨後給出M個商品的整數價值。N和M在[1, 10610^6106]之間,所有的數據大小不超過2302^{30}230,數字間以空格分隔。

輸出格式:

輸出可以得到的最大回報。

輸入樣例:

4 1 2 4 -1
4 7 6 -2 -3

輸出樣例:

43

解題思路:

對於題中所給的例子,仔細分析之後,會發現它所求的滿足一下特點:

優惠券與價值相乘的值是正數

題中又有要求求最大值,那麼就貪心一下,

最大的正數相乘,較小的次之;

最小的負數相乘,較大的次之。

這就需要使用排序解題。

提交代碼:

編譯器:g++

#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1000002;
int arr1[MAXN], arr2[MAXN];
int main()
{
    int n, m;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
        scanf("%d", &arr1[i]);
    scanf("%d", &m);
    for(int i = 0; i < n; ++i)
        scanf("%d", &arr2[i]);
    sort(arr1, arr1 + n, greater<int>());
    sort(arr2, arr2 + n, greater<int>());
    int f = 0, e1 = n - 1, e2 = n - 1;
    long long ans = 0;
    while(f < n && arr1[f] > 0 && arr2[f] > 0)
        ans += arr1[f] * arr2[f], f++;
    while(e1 >= f && arr1[e1] < 0 && arr2[e2] < 0)
        ans += arr1[e1] * arr2[e2], e1--, e2--;
    printf("%lld\n", ans);
    return 0;
}

奧運排行榜   (25分)

每年奧運會各大媒體都會公佈一個排行榜,但是細心的讀者發現,不同國家的排行榜略有不同。比如中國金牌總數列第一的時候,中國媒體就公佈“金牌榜”;而美國的獎牌總數第一,於是美國媒體就公佈“獎牌榜”。如果人口少的國家公佈一個“國民人均獎牌榜”,說不定非洲的國家會成爲榜魁…… 現在就請你寫一個程序,對每個前來諮詢的國家按照對其最有利的方式計算它的排名。

輸入格式:

輸入的第一行給出兩個正整數NNNMMM≤224\le 224224,因爲世界上共有224個國家和地區),分別是參與排名的國家和地區的總個數、以及前來諮詢的國家的個數。爲簡單起見,我們把國家從0 ~ N−1N-1N1編號。之後有NNN行輸入,第iii行給出編號爲i−1i-1i1的國家的金牌數、獎牌數、國民人口數(單位爲百萬),數字均爲[0,1000]區間內的整數,用空格分隔。最後面一行給出MMM個前來諮詢的國家的編號,用空格分隔。

輸出格式:

在一行裏順序輸出前來諮詢的國家的排名:計算方式編號。其排名按照對該國家最有利的方式計算;計算方式編號爲:金牌榜=1,獎牌榜=2,國民人均金牌榜=3,國民人均獎牌榜=4。輸出間以空格分隔,輸出結尾不能有多餘空格。

若某國在不同排名方式下有相同名次,則輸出編號最小的計算方式。

輸入樣例:

4 4
51 100 1000
36 110 300
6 14 32
5 18 40
0 1 2 3

輸出樣例:

1:1 1:2 1:3 1:4

解題思路:

提交代碼:

編譯器:g++

#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 225;
struct infi{
    int ID;
    int g, m, p;
    double avgg, avgm;
    int r[4];
}national[MAXN];
struct ans{
    int r, cal;
}Ans[MAXN];
bool cmp1(struct infi a, struct infi b);
bool cmp2(struct infi a, struct infi b);
bool cmp3(struct infi a, struct infi b);
bool cmp4(struct infi a, struct infi b);
int main()
{
    int n, m;
    int nation;
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; ++i)
    {
        scanf("%d%d%d",&national[i].g, &national[i].m, &national[i].p);
        national[i].avgg = 1.0 * national[i].g / national[i].p;
        national[i].avgm = 1.0 * national[i].m / national[i].p;
        national[i].ID = i;
    }
    sort(national, national + n, cmp1);
    int tmp = national[0].g, r0 = 2, r = 1;
    national[0].r[0] = 1;
    for(int i = 1; i < n; ++i)
    {
        if(tmp != national[i].g) r = r0, tmp = national[i].g;
        national[i].r[0] = r, r0++;
    }
    sort(national, national + n, cmp2);
    tmp = national[0].m, r0 = 2, r = 1;
    national[0].r[1] = 1;
    for(int i = 1; i < n; ++i)
    {
        if(tmp != national[i].m) r = r0, tmp = national[i].m;
        national[i].r[1] = r, r0++;
    }
    sort(national, national + n, cmp3);
    double tmpavg = national[0].avgg;
    r0 = 2, r = 1, national[0].r[2] = 1;
    for(int i = 1; i < n; ++i)
    {
        if(tmpavg != national[i].avgg) r = r0, tmpavg = national[i].avgg;
        national[i].r[2] = r, r0++;
    }
    sort(national, national + n, cmp4);
    tmpavg = national[0].avgm;
    r0 = 2, r = 1, national[0].r[3] = 1;
    for(int i = 1; i < n; ++i)
    {
        if(tmpavg != national[i].avgm) r = r0, tmpavg = national[i].avgm;
        national[i].r[3] = r, r0++;
    }
    for(int i = 0; i < m; ++i)
    {
        scanf("%d", &nation);
        int index = 0, tmpr = MAXN;
        for(int j = 0; j < n; ++j)
        {
            if(national[j].ID == nation)
            {
                nation = j;
                break;
            }
        }
        for(int j = 0; j < 4; ++ j)
            if(tmpr > national[nation].r[j]) index = j, tmpr = national[nation].r[j];
        Ans[i].r = tmpr;
        if(index == 0) Ans[i].cal = 1;
        else if(index == 1) Ans[i].cal = 2;
        else if(index == 2) Ans[i].cal = 3;
        else if(index == 3) Ans[i].cal = 4;
    }
    for(int i = 0; i < m; ++i)
    {
        if(i) printf(" ");
        printf("%d:%d", Ans[i].r, Ans[i].cal);
    }
    return 0;
}
bool cmp1(struct infi a, struct infi b)
{
    return a.g > b.g;
}
bool cmp2(struct infi a, struct infi b)
{
    return a.m > b.m;
}
bool cmp3(struct infi a, struct infi b)
{
    return a.avgg > b.avgg;
}
bool cmp4(struct infi a, struct infi b)
{
    return a.avgm > b.avgm;
}

尋找大富翁   (25分)

2015年胡潤研究院的調查顯示,截至2014年9月,個人資產在600萬元以上高淨值人羣達290萬人。假設給出N個人的個人資產值,請快速找出資產排前M位的大富翁。

輸入格式:

輸入首先給出兩個正整數NNN≤106\le 10^6106)和MMM≤10\le 1010),其中NNN爲總人數,MMM爲需要找出的大富翁數;接下來一行給出NNN個人的個人資產值,以百萬元爲單位,爲不超過長整型範圍的整數。數字間以空格分隔。

輸出格式:

在一行內按非遞增順序輸出資產排前MMM位的大富翁的個人資產值。數字間以空格分隔,但結尾不得有多餘空格。

輸入樣例:

8 3
8 12 7 3 20 9 5 18

輸出樣例:

20 18 12

解題思路:

由於題中的M值較小,此處採用的是冒泡排序,而未使用堆排序。

認爲使用冒泡排序時間複雜度可能更接近線性。

提交代碼:

編譯器:g++

#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXN = 1000002;
int arr[MAXN];
void Swap(int &a, int &b);
int main()
{
	int n, m;
	cin>>n>>m;
	m = m < n ? m : n;
	for(int i = 0; i < n; ++i)
		scanf("%d",&arr[i]);
	for(int i = 0; i < m; ++i)
	{
		for(int j = n - 1; j > i; --j)
		{
			if(arr[j] > arr[j - 1])
				Swap(arr[j], arr[j - 1]);
		}
	}
	for(int i = 0; i < m; ++i)
	{
		if(i) printf(" ");
		printf("%d",arr[i]);
	}
	return 0;
}
void Swap(int &a, int &b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

PAT排名彙總   (25分)

計算機程序設計能力考試(Programming Ability Test,簡稱PAT)旨在通過統一組織的在線考試及自動評測方法客觀地評判考生的算法設計與程序設計實現能力,科學的評價計算機程序設計人才,爲企業選拔人才提供參考標準(網址http://www.patest.cn)。

每次考試會在若干個不同的考點同時舉行,每個考點用局域網,產生本考點的成績。考試結束後,各個考點的成績將即刻彙總成一張總的排名表。

現在就請你寫一個程序自動歸併各個考點的成績並生成總排名表。

輸入格式:

輸入的第一行給出一個正整數N(≤\le100),代表考點總數。隨後給出N個考點的成績,格式爲:首先一行給出正整數K(≤\le300),代表該考點的考生總數;隨後K行,每行給出1個考生的信息,包括考號(由13位整數字組成)和得分(爲[0,100]區間內的整數),中間用空格分隔。

輸出格式:

首先在第一行裏輸出考生總數。隨後輸出彙總的排名表,每個考生的信息佔一行,順序爲:考號、最終排名、考點編號、在該考點的排名。其中考點按輸入給出的順序從1到N編號。考生的輸出須按最終排名的非遞減順序輸出,獲得相同分數的考生應有相同名次,並按考號的遞增順序輸出。

輸入樣例:

2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

輸出樣例:

9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4

解題思路:

此處不得不用歸併排序啦

1)首先,在一個考場的按要求排序

2)之後,將一個考場的排序與各個考場合並過的信息排序

此處的排名需要注意同名次的情況。

提交代碼:

編譯器:g++

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
const int MAXN = 30003;
struct infi{
    char ID[15];
    int plant, score;
    int r;
    bool operator <(const struct infi p) const{
        if(score != p.score)
            return score > p.score;
        else
            return strcmp(ID, p.ID) < 0;
    }
}peo[MAXN], tmp[303], tmpMer[MAXN];
int Merge(int l, int m);
int main()
{
    int n, m, l = 0;
    scanf("%d", &n);
    for(int plant = 1; plant <= n; ++plant)
    {
        scanf("%d", &m);
        for(int i = 0; i < m; ++i)
        {
            scanf("%s %d", tmp[i].ID, &tmp[i].score);
            tmp[i].plant = plant;
        } //以上讀入信息
        sort(tmp, tmp + m);
        int r0 = 1, r = 1;
        int s = tmp[0].score;
        for(int i = 0; i < m; ++i)
        {
            if(tmp[i].score != s) r = r0, s = tmp[i].score;
            tmp[i].r = r, r0++;
        } //以上是對考場排序
        l = Merge(l, m); //此處是合併到本次考試中
    }
    int r0 = 1, r = 1;
    int s = peo[0].score;
    printf("%d\n", l);
    for(int i = 0; i < l; ++i)
    {
        if(peo[i].score != s) r = r0, s = peo[i].score;
        printf("%s %d %d %d\n", peo[i].ID, r, peo[i].plant, peo[i].r);
        r0++;
    }
    return 0;
}
int Merge(int l, int m)
{
    int s1 = 0, s2 = 0, index = 0;
    while(s1 < l && s2 < m)
    {
        if(peo[s1].score > tmp[s2].score)
        {
            tmpMer[index] = peo[s1];
            s1++, index++;
        }
        else if(peo[s1].score < tmp[s2].score)
        {
            tmpMer[index] = tmp[s2];
            s2++, index++;
        }
        else
        {
            if(strcmp(peo[s1].ID, tmp[s2].ID) < 0)
                tmpMer[index] = peo[s1], s1++, index++;
            else tmpMer[index] = tmp[s2], s2++, index++;
        }
    }
    while(s1 < l)
    {
        tmpMer[index] = peo[s1];
        s1++, index++;
    }
    while(s2 < m)
    {
        tmpMer[index] = tmp[s2];
        s2++, index++;
    }
    for(int i = 0; i < l + m; ++i)
    {
        peo[i] = tmpMer[i];
    }
    return l + m;
}

PAT Judge   (25分)

The ranklist of PAT is generated from the status list, which shows the scores of the submittions. This time you are supposed to generate the ranklist for PAT.

Input Specification:

Each input file contains one test case. For each case, the first line contains 3 positive integers,NNN (≤104\le 10^4104), the total number of users, KKK (≤5\le 55), the total number of problems, and MMM (≤105\le 10^5105), the total number of submittions. It is then assumed that the user id's are 5-digit numbers from 00001 toNNN, and the problem id's are from 1 to KKK. The next line contains KKK positive integers p[i] (i=1, ..., KKK), where p[i] corresponds to the full mark of the i-th problem. Then MMM lines follow, each gives the information of a submittion in the following format:

user_id problem_id partial_score_obtained

where partial_score_obtained is either −1-11 if the submittion cannot even pass the compiler, or is an integer in the range [0,p[problem_id]]. All the numbers in a line are separated by a space.

Output Specification:

For each test case, you are supposed to output the ranklist in the following format:

rank user_id total_score s[1] ... s[K]

where rank is calculated according to the total_score, and all the users with the sametotal_score obtain the samerank; and s[i] is the partial score obtained for thei-th problem. If a user has never submitted a solution for a problem, then "-" must be printed at the corresponding position. If a user has submitted several solutions to solve one problem, then the highest score will be counted.

The ranklist must be printed in non-decreasing order of the ranks. For those who have the same rank, users must be sorted in nonincreasing order according to the number of perfectly solved problems. And if there is still a tie, then they must be printed in increasing order of their id's. For those who has never submitted any solution that can pass the compiler, or has never submitted any solution, they must NOT be shown on the ranklist. It is guaranteed that at least one user can be shown on the ranklist.

Sample Input:

7 4 20
20 25 25 30
00002 2 12
00007 4 17
00005 1 19
00007 2 25
00005 1 20
00002 2 2
00005 1 15
00001 1 18
00004 3 25
00002 2 25
00005 3 22
00006 4 -1
00001 2 18
00002 1 20
00004 1 15
00002 4 18
00001 3 4
00001 4 2
00005 2 -1
00004 2 0

Sample Output:

1 00002 63 20 25 - 18
2 00005 42 20 0 22 -
2 00007 42 - 25 - 17
2 00001 42 18 18 4 2
5 00004 40 15 0 25 -

解題思路:

提交代碼:

編譯器:g++

#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int MAXNP = 10002;
const int MAXNS = 6;
struct infi{
    int ID;
    int total, solve;
    int Pid[MAXNS];
    bool Psol[MAXNS], summit;
    bool operator <(const struct infi s1) const{
        bool order = true;
        if(total != s1.total) order = total > s1.total;
        else if(solve != s1.solve) order = solve > s1.solve;
        else order = ID < s1.ID;
        return order;
    }
}stu[MAXNP]; //定義每個考生的信息,其中的成員分別存儲考號,總分,解題數,每一題得分,每題的提交情況,是否提交
int Score[MAXNS]; //每題的分數
int main( )
{
    int n, k, m;
    int id, pid, sco, index = 1, rank = 1;
    scanf("%d%d%d", &n, &k, &m);
    for(int i = 0; i <= n; ++i)
    {
        stu[i].ID = i;
        stu[i].total = stu[i].solve = 0;
        stu[i].summit = false;
        for(int j = 0; j <= k; ++j)
            stu[i].Pid[j] = -2, stu[i].Psol[j] = false;
    }
    for(int i = 1; i <= k; ++i)
        scanf("%d",&Score[i]);
    for(int i = 0; i < m; ++i)
    {
        scanf("%d%d%d", &id, &pid, &sco);
        if(stu[id].Pid[pid] < sco) 如果該考生的某題過去分數少於現在得分,則更新(注意題中編譯出錯的情況)
        {
            if(sco == Score[pid]) stu[id].solve++; //表示解決此題
            if(sco == -1) sco = 0; //編譯出錯
            stu[id].Pid[pid] = sco; //更新分數
            if(!stu[id].Psol[pid]) stu[id].Psol[pid] = true; //此題是否提交過
            stu[id].summit = true; //該考生本次考試提交過代碼
        }
    }
    for(int i = 1; i <= n; ++i) //得到總分
    {
        for (int j = 1; j <= k; ++j)
            if(stu[i].Psol[j])
                stu[i].total += stu[i].Pid[j];
    }
    sort(stu + 1, stu + n + 1);
    sco = stu[1].total;
    for(int i = 1; i <= n && stu[i].summit; ++i) //輸出
    {
        if(sco != stu[i].total) rank = index;
        index++;
        printf("%d %05d %d", rank, stu[i].ID, stu[i].total);
        for(int j = 1; j <= k; ++j)
            if(stu[i].Psol[j]) printf(" %d", stu[i].Pid[j]);
            else printf(" -");
        printf("\n");
        sco = stu[i].total;
    }
    return 0;
}

Insert or Merge   (25分)

According to Wikipedia:

Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. Each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there. It repeats until no input elements remain.

Merge sort works as follows: Divide the unsorted list into N sublists, each containing 1 element (a list of 1 element is considered sorted). Then repeatedly merge two adjacent sublists to produce new sorted sublists until there is only 1 sublist remaining.

Now given the initial sequence of integers, together with a sequence which is a result of several iterations of some sorting method, can you tell which sorting method we are using?

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integerNNN (≤100\le 100100). Then in the next line, NNN integers are given as the initial sequence. The last line contains the partially sorted sequence of theNNN numbers. It is assumed that the target sequence is always ascending. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in the first line either "Insertion Sort" or "Merge Sort" to indicate the method used to obtain the partial result. Then run this method for one more iteration and output in the second line the resuling sequence. It is guaranteed that the answer is unique for each test case. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

Sample Output 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

Sample Input 2:

10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6

Sample Output 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

解題思路:

直接對輸入的數據用歸併排序模擬,

如果排序中途的序列與所給序列相同,則是歸併排序。

如果直到有序依舊沒有與所給的序列相同,則是插入排序。

不管哪種排序都要將下一步排序結果輸出。

提交代碼:

編譯器:g++

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAXN = 102;
int num1[MAXN], num2[MAXN];
bool Merge(int n);
int main()
{
    int n;
    cin>>n;
    for(int i = 0; i < n; ++i)
        cin>>num1[i];
    for(int i = 0; i < n; ++i)
        cin>>num2[i];
    if(Merge(n))
    {
        cout<<"Merge Sort"<<endl;
        for(int i = 0; i < n - 1; ++i)
            cout<<num1[i]<<' ';
        cout<<num1[n-1]<<endl;
    }
    else
    {
        cout<<"Insertion Sort"<<endl;
        for(int i = 1; i < n; ++i)
        {
            if(num2[i - 1] > num2[i])
            {
                int tmp = num2[i];
                for(; i >0 && tmp < num2[i - 1]; --i)
                    num2[i] = num2[i - 1];
                num2[i] = tmp;
                break;
            }
        }
        for(int i = 0; i < n - 1; ++i)
            cout<<num2[i]<<' ';
        cout<<num2[n - 1]<<endl;
    }
    return 0;
}
bool Merge(int n)
{
    int i;
    bool isMerge = false;
    for(int setp = 1; true; ++setp)
    {
        int len = 1 << setp;
        int f = 0, e = len;
        if(e > n)
        {
            sort(num1, num1 + n);
            break;
        }
        while(f < n)
        {
            sort(num1 + f,num1 + e);
            f += len, e += len;
            if(e > n) e = n;
        }
        if(isMerge) break;
        for(i = 0; i < n; ++i)
            if(num1[i] != num2[i]) break;
        if(i >= n) isMerge = true;
    }
    return isMerge;
}

 Insertion or Heap Sort   (25分)

According to Wikipedia:

Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list. Each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there. It repeats until no input elements remain.

Heap sort divides its input into a sorted and an unsorted region, and it iteratively shrinks the unsorted region by extracting the largest element and moving that to the sorted region. it involves the use of a heap data structure rather than a linear-time search to find the maximum.

Now given the initial sequence of integers, together with a sequence which is a result of several iterations of some sorting method, can you tell which sorting method we are using?

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integerNNN (≤100\le 100100). Then in the next line, NNN integers are given as the initial sequence. The last line contains the partially sorted sequence of theNNN numbers. It is assumed that the target sequence is always ascending. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in the first line either "Insertion Sort" or "Heap Sort" to indicate the method used to obtain the partial result. Then run this method for one more iteration and output in the second line the resuling sequence. It is guaranteed that the answer is unique for each test case. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

Sample Output 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

Sample Input 2:

10
3 1 2 8 7 5 9 4 6 0
6 4 5 1 0 3 2 7 8 9

Sample Output 2:

Heap Sort
5 4 3 1 0 2 6 7 8 9

解題思路:

此題與上題的思路相識。

注意堆排序的操作,當然直接用插入排序模擬也可。

提交代碼:

編譯器:g++

#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXN = 102;
int num1[MAXN], num2[MAXN];
bool HeapSort(int n);
void Swap(int &a, int &b);
void adjust(int index, int n);
int main()
{
    int n;
    cin>>n;
    for(int i = 1; i <= n; ++i)
        cin>>num1[i];
    for(int i = 1; i <= n; ++i)
        cin>>num2[i];
    if(HeapSort(n))
    {
        cout<<"Heap Sort"<<endl;
        for(int i = 1; i < n; ++i)
            cout<<num1[i]<<' ';
        cout<<num1[n]<<endl;
    }
    else
    {
        cout<<"Insertion Sort"<<endl;
        for(int i = 2; i <= n; ++i)
        {
            if(num2[i - 1] > num2[i])
            {
                int tmp = num2[i];
                for(; i >1 && tmp < num2[i - 1]; --i)
                    num2[i] = num2[i - 1];
                num2[i] = tmp;
                break;
            }
        }
        for(int i = 1; i < n; ++i)
            cout<<num2[i]<<' ';
        cout<<num2[n]<<endl;
    }
    return 0;
}
bool HeapSort(int n)
{
    int i;
    bool isHeap = false;
    for(int index = n >> 1; index > 0; --index)
        adjust(index, n);
    while(n > 1)
    {
        Swap(num1[1], num1[n]);
        n--;
        adjust(1, n);
        if(isHeap) break;
        for(i = 1; i <= n; ++i)
            if(num1[i] != num2[i]) break;
        if(i > n) isHeap = true;
    }
    return isHeap;
}
void adjust(int index, int n)
{
    while((index << 1) <= n)
    {
        int i = index;
        if(num1[index << 1] > num1[i])
        {
            int tmp = num1[index << 1];
            index <<= 1;
            if(index + 1 <= n && num1[index + 1] > tmp)
                index++;
            Swap(num1[index], num1[i]);
        }
        else if((index << 1) + 1 <= n && num1[(index << 1) + 1] > num1[index])
        {
            Swap(num1[index], num1[(index << 1) + 1]);
            index = (index << 1) + 1;
        }
        else
        {
            break;
        }
    }
}
void Swap(int &a, int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

Sort with Swap(0, i)   (25分)

Given any permutation of the numbers {0, 1, 2,..., N−1N-1N1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the firstNNN nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive NNN (≤105\le 10^5105) followed by a permutation sequence of {0, 1, ..., N−1N-1N1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:

10
3 5 7 2 6 4 9 0 8 1

Sample Output:

9

解題思路:

這道題比較有趣。

有一個數組記錄每個數組所在的位置,

然後考慮零的位置,只要零不在下標爲零的位置則,將零所在下標的對應的數字與零交換。

如果零在下標爲零的位置,則與不在正確位置的數字對調,重複上述步驟,直到排序完成。

提交代碼:

編譯器:g++

#include <iostream>
#include <stdio.h>
using namespace std;
const int MAXN = 100002;
int num[MAXN], Index[MAXN];
void Swap(int &a, int &b);
int main()
{
    int n;
    int cnt = 0;
    scanf("%d", &n);
    for(int i = 0; i < n; ++i)
    {
        scanf("%d", &num[i]); //數字序列
        Index[num[i]] = i; //數字所在序列的下標
    }
    for(int i = 0;i < n; ++i)
    {
        while(Index[0] != 0) //下標爲零的位置不是零,則交換
        {
            int index = Index[Index[0]]; //在下標爲零的數字的位置
            Swap(num[index], num[Index[0]]);//數字和零交換到正確的位置
            Index[Index[0]] = Index[0]; //並且更新數字在序列中的位置
            Index[0] = index;
            cnt++; //交換一次
        }
        for(; i < n && num[i] == i; ++i); //尋找是否還有使序列無序的元素
        if(i < n) //如果有,則與零交換
        {
            Swap(num[0], num[i]);
            Index[num[0]] = 0;
            Index[0] = i;
            cnt++;
        }
    }
    printf("%d\n",cnt);
    return 0;
}
void Swap(int &a, int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章