数据结构---排序

来源:互联网 发布:网络舆情监测方法 编辑:程序博客网 时间:2024/06/05 19:02

排序


排序的知识点整理:可以看这位大神的白话经典算法系列中的排序

以下只有解题思路。

魔法优惠券   (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 -14 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 451 100 100036 110 3006 14 325 18 400 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 38 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编号。考生的输出须按最终排名的非递减顺序输出,获得相同分数的考生应有相同名次,并按考号的递增顺序输出。

输入样例:

251234567890001 951234567890005 1001234567890003 951234567890002 771234567890004 8541234567890013 651234567890011 251234567890014 1001234567890012 85

输出样例:

91234567890005 1 1 11234567890014 1 2 11234567890001 3 1 21234567890003 3 1 21234567890004 5 1 41234567890012 5 2 21234567890002 7 1 51234567890013 8 2 31234567890011 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; ands[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 2020 25 25 3000002 2 1200007 4 1700005 1 1900007 2 2500005 1 2000002 2 200005 1 1500001 1 1800004 3 2500002 2 2500005 3 2200006 4 -100001 2 1800002 1 2000004 1 1500002 4 1800001 3 400001 4 200005 2 -100004 2 0

Sample Output:

1 00002 63 20 25 - 182 00005 42 20 0 22 -2 00007 42 - 25 - 172 00001 42 18 18 4 25 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:

103 1 2 8 7 5 9 4 6 01 2 3 7 8 5 9 4 6 0

Sample Output 1:

Insertion Sort1 2 3 5 7 8 9 4 6 0

Sample Input 2:

103 1 2 8 7 5 9 4 0 61 3 2 8 5 7 4 9 0 6

Sample Output 2:

Merge Sort1 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:

103 1 2 8 7 5 9 4 6 01 2 3 7 8 5 9 4 6 0

Sample Output 1:

Insertion Sort1 2 3 5 7 8 9 4 6 0

Sample Input 2:

103 1 2 8 7 5 9 4 6 06 4 5 1 0 3 2 7 8 9

Sample Output 2:

Heap Sort5 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:

103 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;}

0 0
原创粉丝点击