算法笔记4.1排序

排序

A1062

本题关键是如何分类和写cmp函数。在结构体里增加flag表示为每个学生的等级。在读入的数据的时候对数据进行分类即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010;
struct Person
{
    int de, cai, sum;
    int id;
    int flag;
}stu[N];
bool cmp(Person a, Person b)
{
    if(a.flag != b.flag) return a.flag < b.flag;
    else if(a.sum != b.sum) return a.sum > b.sum;
    else if(a.de != b.de) return a.de > b.de;
    else return a.id < b.id;
}
int main()
{
    int n, high, low;
    scanf("%d%d%d", &n, &low, &high);
    int num = n;
    for(int i = 0; i < n; i++)
    {
        scanf("%d %d %d", &stu[i].id, &stu[i].de, &stu[i].cai);
        stu[i].sum = stu[i].de + stu[i].cai;
        if(stu[i].de < low || stu[i].cai < low)
        {
            stu[i].flag = 5;
            num --;
        }
        else
        {
            if(stu[i].de >= high && stu[i].cai >= high)
                stu[i].flag = 1;
            else if(stu[i].de >= high && stu[i].cai < high)
                stu[i].flag = 2;
            else if(stu[i].de >= stu[i].cai)
                stu[i].flag = 3;
            else
                stu[i].flag = 4;
        }
    }
    sort(stu, stu + n, cmp);
    printf("%d\n", num);
    for(int i = 0; i < num; i++)
    {
        printf("%d %d %d\n",stu[i].id, stu[i].de, stu[i].cai);
    }
    return 0;
}

A1012

本题需要建立一个二维数组来存储每个学生的rank排名,同时需要将学生的id用int存储,这样rank[id][now]就可以直接得出学生的具体科目的成绩,同时需要比较不同科目的时候可以在bool函数设置一个全局变量,在函数里改变全局变量就可以排序不同的内容。需要注意如何四舍五入。在读入所有的数据后进行排序,因为有四个学科所以得出可以四次外循环,外循环内进行排序,在内循环内进行rank的更新。输出时可以建立字符数组用来int和char的映射,因为优先级是A>C>M>E。所以字符数组也为这个顺序并从a开始遍历寻找找好排名。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct student
{
    int id;
    int grade[4];
}stu[2010];
char course[4] = {'A', 'C', 'M', 'E'};
int Rank[10000000][4] = {0};
int now;
bool cmp(student a, student b)
{
    return a.grade[now] > b.grade[now];
}
int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d%d%d", &stu[i].id, &stu[i].grade[1], &stu[i].grade[2], &stu[i].grade[3]);
        stu[i].grade[0] = round((stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) / 3.0);
       // printf("%d %d %d %d %d\n",stu[i].id, stu[i].grade[0], stu[i].grade[1], stu[i].grade[2], stu[i].grade[3]);
    }
    for(now = 0; now < 4; now ++)
    {
        sort(stu, stu + n, cmp);
        Rank[stu[0].id][now] = 1;
        for(int j = 1; j < n; j++)
        {
            if(stu[j].grade[now] == stu[j - 1].grade[now])
                Rank[stu[j].id][now] = Rank[stu[j - 1].id][now];
            else
                Rank[stu[j].id][now] = j + 1;
        }
    }
    int query;
    for(int i = 0; i < m; i++)
    {
        scanf("%d", &query);
        if(Rank[query][0] == 0)
            printf("N/A\n");
        else
        {
            int k = 0;
            for(int j = 1; j < 4; j++)
            {
                if(Rank[query][j] < Rank[query][k])
                    k = j;
            }
            printf("%d %c\n",Rank[query][k] , course[k]);
        }
    }
    return 0;
}

补充:关于数字处理的一些技巧
1.向上取整:ceil()
2.向下取整:floor()
3.四舍五入:round()
4.保留有效数字位的写法

#include<stdio.h>
#include<math.h>

int main()
{
	double x=1.5684;
	printf("对1.5684保留两位有效数字:");
	printf("%.2lf\n",round(x*100)/100);
	return 0;
 } 

输出结果:

1.5684保留两位有效数字:1.57

手写round函数:

#include<stdio.h>

double round(double x)
{
	return (int)(x+0.5);
}

A1016

本题是一道比较难的题目。读入数据时可以用bool的true和false来替换on/off-line。先将同一个名字的数据排序到一起,所以cmp首先考虑name的排序其次是month,dd,mm。处理数据是一个难题,首先用三个指针,on,off,next。next用于表示一个用户开始地址,在第一个循环时next指针一边搜索下一个用户的开始地址一边搜索能不能输出。在判断能不能输出时分成两部先找到on-line同时下一个是off-line的时候则能输出。

while(next < n && strcmp(rec[on].name, rec[next].name) == 0)
        {
            if(rec[next].status == true && rec[next + 1].status == false && strcmp(rec[next + 1].name, rec[next].name) == 0)
                flag = true;
            next++;
        }

可以按上面这种方法写,括号里的最后一个strcmp==0是为了保证是同一个用户。也可以分成两部来写,用int<2判断。
第一个用户已经遍历完了,这是on就可以移动了,判断有无输出。
如果没有输出则后面的直接用continue跳过。如果有输出,从on开始寻找符合输出条件的数据,因为是成对输出所以只需要遍历到next - 2即可,如果on=next-1,说明已经到了最后则更新on进行下一个用户遍历,如果没到说明有输出的满足了。同时写一个记录time和money 的函数,用引用参数即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1010;
int toll[25] = {0};
struct Record
{
    char name[25];
    int month, dd, hh, mm;
    bool status;
}rec[N], temp;
bool cmp(Record a, Record b)
{
    int s= strcmp(a.name, b.name);
    if(s != 0) return s < 0;
    else if(a.month != b.month) return a.month < b.month;
    else if(a.dd != b.dd) return a.dd < b.dd;
    else if(a.hh != b.hh) return a.hh < b.hh;
    else return a.mm < b.mm;
}
void get_ans(int on, int off, int& time, int& money)
{
    temp = rec[on];
    while(temp.dd < rec[off].dd || temp.hh < rec[off].hh || temp.mm < rec[off].mm)
    {
        time++;
        money += toll[temp.hh];
        temp.mm++;
        if(temp.mm >= 60)
        {
            temp.mm = 0;
            temp.hh++;
        }
        if(temp.hh >= 24)
        {
            temp.hh = 0;
            temp.dd++;
        }
    }
}
int main()
{
    for(int i = 0; i < 24; i++)
    {
        scanf("%d", &toll[i]);
    }

    int n;
    char line[10];
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%s", rec[i].name);
        scanf("%d:%d:%d:%d", &rec[i].month, &rec[i].dd, &rec[i].hh, &rec[i].mm);
        scanf("%s", line);
        if(strcmp(line, "on-line") == 0)
            rec[i].status = true;
        else
            rec[i].status = false;
    }
    sort(rec, rec + n, cmp);
    int on = 0, next, off;
    while(on < n)
    {
        int needPrint = 0;
        next = on;
        while(next < n && strcmp(rec[next].name, rec[on].name) == 0)
        {
            if(needPrint == 0 && rec[next].status == true)
                needPrint = 1;
            else if(needPrint == 1 && rec[next].status == false)
                needPrint = 2;
            next++;
        }
        if(needPrint < 2)
        {
            on = next;
            continue;
        }
        int Allmoney = 0;
        printf("%s %02d\n", rec[on].name, rec[on].month);
        while(on < next)
        {
            while(on < next - 1 && !(rec[on].status == true && rec[on + 1].status == false))
                on++;
            off = on + 1;
            if(off == next)
            {
                on = next;
                break;
            }
            int money = 0, time = 0;
            printf("%02d:%02d:%02d ", rec[on].dd, rec[on].hh, rec[on].mm);
            printf("%02d:%02d:%02d ", rec[off].dd, rec[off].hh, rec[off].mm);
            get_ans(on, off, time, money);
            Allmoney += money;
            printf("%d $%.2f\n", time, money / 100.0);
            on = off + 1;
        }
        printf("Total amount: $%.2f\n", Allmoney / 100.0);
    }
    return 0;
}

A1055

本题需要预处理,因为告诉我们输出m个所以我们需要将age的前m个放入另一个数组,其余的可以直接丢弃了。但是需要先将整个数组进行sort排序再进行预处理,否则valid数组里的不一定是worth排名前100的数据。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010;
int age[200] = {0};
struct Person
{
    char name[10];
    int age;
    int worth;
}per[N],valid[N];
bool cmp(Person a, Person b)
{
    if(a.worth != b.worth) return a.worth > b.worth;
    else if(a.age != b.age) return a.age < b.age;
    else return strcmp(a.name, b.name) < 0;
}
int main()
{
    int n, k;
    scanf("%d %d", &n, &k);
    for(int i = 0; i < n; i++)
    {
        scanf("%s %d %d", per[i].name, &per[i].age, &per[i].worth);
    }
    sort(per, per + n, cmp);
    int validnum = 0;
    for(int i = 0; i < n; i++)
    {
        if(age[per[i].age] < 100)
        {
            valid[validnum++] = per[i];
            age[per[i].age]++;
        }
    }
    for(int i = 1; i <= k; i++)
    {
        int m, amin, amax;
        scanf("%d %d %d", &m, &amin, &amax);
        printf("Case #%d:\n", i);
        int printnum = 0;
        for(int j = 0; j < validnum && printnum < m; j++)
        {
            if(valid[j].age >= amin && valid[j].age <= amax)
            {
                printf("%s %d %d\n", valid[j].name, valid[j].age, valid[j].worth); 
                printnum ++;
            }
        }
        if(printnum == 0)
            printf("None\n");
    }
    return 0;
}

A1028

写三个cmp函数即可

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Record
{
    int id;
    char name[10];
    int score;
}stu[100010];
bool cmp1(Record a, Record b)
{
    return a.id < b.id;
}
bool cmp2(Record a, Record b)
{
    int s = strcmp(a.name, b.name);
    if(s != 0) return s < 0;
    else return a.id < b.id;
}
bool cmp3(Record a, Record b)
{
    if(a.score != b.score) return a.score < b.score;
    else return a.id < b.id;
}
int main()
{
    int n, c;
    scanf("%d %d", &n, &c);
    for(int i = 0; i < n; i++)
    {
        scanf("%d %s %d", &stu[i].id, stu[i].name, &stu[i].score);
    }
    if(c == 1) sort(stu, stu + n, cmp1);
    if(c == 2) sort(stu, stu + n, cmp2);
    if(c == 3) sort(stu, stu + n, cmp3);
    for(int i = 0; i < n; i++)
    {
        printf("%06d %s %d\n", stu[i].id, stu[i].name, stu[i].score);
    }
    return 0;
}

A1025

设置locarank,final_rank最后用个r来表示,同时用num来和k来确定每次读入数据的范围【num-k,num】。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct student
{
    char id[15];
    int score;
    int localnumber;
    int localrank;
}stu[30010];
bool cmp(student a, student b)
{
    if(a.score != b.score) return a.score > b.score;
    else return strcmp(a.id, b.id) < 0;
}
int main()
{
    int n, k, num = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &k);
        for(int j = 0; j < k; j++)
        {
            scanf("%s %d", stu[num].id, &stu[num].score);
            stu[num].localnumber = i;
            num ++;
        }
        sort(stu + num - k, stu + num, cmp);
        stu[num - k].localrank = 1;
        for(int j = num - k + 1; j < num; j++)
        {
            if(stu[j].score == stu[j - 1].score)
            {
                stu[j].localrank = stu[j - 1].localrank;
            }else
                stu[j].localrank = j + 1 - (num - k);
        }
    }
    printf("%d\n", num);
    sort(stu, stu + num, cmp);
    int r = 1;
    for(int i = 0; i < num; i++)
    {
        if(i > 0 && stu[i].score != stu[i - 1].score)
            r = i + 1;
        printf("%s ", stu[i].id);
        printf("%d %d %d\n", r, stu[i].localnumber, stu[i].localrank);
    }
    return 0;
}

A1075

本题由于要区分没有提交和编译不通过的情况,以及是否能够输出。所以先设置一个bool变量用于确定是否输出。由于id是从1到n所以可以用u_id读入后直接将score赋值到以u_id为下标的数组元素。同时需要定义sum和solve,在每次读入一个数据时对以u_id的这个元素进行更新。首先判断如果可以输出让bool变量为true,其次为了判定是为提交还是编译不通过,初始化score为-1,获得的分数为-1并且score为-1,则让score为0,所以最后如果为-1说明未提交,如果是0说明为编译未通过。 如果是第一次达到满分则solve++,如果当前分数比score存储的大,则覆盖。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 10010;
int n, m, k;
int full[6];
struct Student
{
    int id;
    int solve;
    int score[6];
    int sum;
    bool status;
}stu[N];
bool cmp(Student a, Student b)
{
    if(a.sum != b.sum) return a.sum > b.sum;
    else if(a.solve != b.solve) return a.solve > b.solve;
    else return a.id < b.id;
}
void init()
{
    for(int i = 1; i <= n; i++)
    {
        stu[i].sum = 0                                                                                                                                                   ;
        stu[i].id = i;
        stu[i].solve = 0;
        stu[i].status = false;
        memset(stu[i].score, -1, sizeof(stu[i].score)); 
    }
}
int main()
{
    scanf("%d%d%d", &n, &k, &m);
    init();
    for(int i = 1; i <= k; i++)
        scanf("%d", &full[i]);
    for(int i = 1; i <= m; i++)
    {
        int u_id, p_id, gain_score;
        scanf("%d %d %d", &u_id, &p_id, &gain_score);
        if(gain_score != -1)
            stu[u_id].status = true;
        if(gain_score == -1 && stu[u_id].score[p_id] == -1)
            stu[u_id].score[p_id] = 0;
        if(gain_score == full[p_id] && stu[u_id].score[p_id] != full[p_id])
            stu[u_id].solve++;
        if(gain_score > stu[u_id].score[p_id])
            stu[u_id].score[p_id] = gain_score;
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= k; j++)
            if(stu[i].score[j] != -1)
                stu[i].sum += stu[i].score[j];
    }
    sort(stu + 1, stu + n + 1, cmp);
    int r = 1;
    for(int i = 1; i <= n && stu[i].status == true; i++)
    {
       if(i > 1 && stu[i].sum != stu[i - 1].sum)
           r = i;
        printf("%d %05d %d", r, stu[i].id, stu[i].sum);
        for(int j = 1; j <= k; j++)
        {
            if(stu[i].score[j] == -1)
                printf(" -");
            else
                printf(" %d", stu[i].score[j]);
        }
        printf("\n");
    }
    return 0;
}

A1083

水题

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct Student
{
    char name[15];
    char id[15];
    int score;
}stu[110];
bool cmp(Student a, Student b)
{
    return a.score > b.score;
}
int main()
{
    int n, left, right;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        scanf("%s %s %d", stu[i].name, stu[i].id, &stu[i].score);
    }
    scanf("%d %d",&left, &right);
    bool print = false;
    sort(stu + 1, stu + n + 1, cmp);
    for(int i = 1; i <= n; i++)
    {
        if(stu[i].score >= left && stu[i].score <= right)
        {
            printf("%s %s\n", stu[i].name, stu[i].id);
            print = true;
        }
    }
    if(!print)
        printf("NONE\n");
    return 0;
}

A1080

本题需要写两个结构体,一个是学生,一个是学校。因为要考虑到学校找人超出的情况,所以需要在学校的结构体内设置指标,人数和上一个录取人的信息。又因为sort以后每个学生的下标就变了,所以要以学生内部需要设置id来记录是第几个被输入的用于后面被输出。在所有信息读入后,先对学生的rank进行处理,然后对每一个学生进行外循环,对学生的每个志愿进行内循环。先读入志愿学校的标号,志愿和该学校最后一个录取的人数的序号。根据条件判断能否录取,如果能够录取则把该学生在排好序的数组的下标读入到学校的id数组里用于最后输出原来的下标。并且更新num和lastadmit。最后遍历学校,如果学校的的招生人数大于0则排序并进行输出。

#include<cstdio>
#include<algorithm>
using namespace std;
struct Student
{
    int GE, GI, sum;
    int r, stuID;
    int cho[6];
}stu[40010];
struct School
{
    int quota;
    int stuNum;
    int lastAdmit;
    int ID[40010];
}sch[110];
bool cmpStu(Student a, Student b)
{
    if(a.sum != b.sum) return a.sum > b.sum;
    else return a.GE > b.GE;
}
bool cmpID(int a, int b)
{
    return stu[a].stuID < stu[b].stuID;
}
int main()
{
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 0; i < m; i++)
    {
        scanf("%d", &sch[i].quota);
        sch[i].stuNum = 0;
        sch[i].lastAdmit = -1;
    }
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d", &stu[i].GE, &stu[i].GI);
        stu[i].sum = stu[i].GE + stu[i].GI;
        stu[i].stuID = i;
        for(int j = 0; j < k; j++)
            scanf("%d", &stu[i].cho[j]);
    }
    sort(stu, stu + n, cmpStu);
    for(int i = 0; i < n; i++)
    {
        if(i > 0 && stu[i].sum == stu[i-1].sum && stu[i].GE == stu[i-1].GE)
            stu[i].r = stu[i - 1].r;
        else
            stu[i].r = i;
    }
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < k; j++)
        {
            int choice = stu[i].cho[j];
            int last = sch[choice].lastAdmit;
            int num = sch[choice].stuNum;
            if(num < sch[choice].quota || (stu[i].r == stu[last].r))
            {
                sch[choice].ID[num] = i;
                sch[choice].lastAdmit = i;
                sch[choice].stuNum++;
                break;
            }
        }
    }
    for(int i = 0; i < m; i++)
    {
        if(sch[i].stuNum > 0)
        {
            sort(sch[i].ID, sch[i].ID + sch[i].stuNum, cmpID);
            for(int j = 0; j < sch[i].stuNum; j++)
            {
                printf("%d", stu[sch[i].ID[j]].stuID);
                if(j < sch[i].stuNum - 1)
                    printf(" ");
            }
        }
        printf("\n");
    }
    return 0;
}

A1095

本题和A1016相似,都是处理相同名字的多个数据。由于需要输出最大的停车时间所以需要建立一个string到int 的map映射。time直接用秒做单位会化简很多代码。首先读入数据排序,在遍历的时候把in和out配对的存入另一个数组并且不断更新maxtime的值。因为这个是以同一个车牌的不同时间的处理。所以可以得到每个车的总时间。然后对有效数组按时间进行排序,因为给的查询时间是递增的所以每次不需要初始化0,上一个循环可以继续的参数可以继续使用。遇到in时numcar加1遇到out时numcar减1.最后用迭代器遍历map。找到最大时间的下标输出即可。注意输出格式需要用char数组的格式。

#include<cstdio>
#include<map>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int N = 10010;
struct Car
{
    char id[10];
    int time;
    char status[5];
}all[N], valid[N];
map<string, int>parkTime;
int timeToInt(int hh, int mm, int ss)
{
    return hh * 3600 + mm * 60 + ss;
}
bool cmpByCarAndTime(Car a, Car b)
{
    int s = strcmp(a.id, b.id);
    if(s != 0) return s < 0;
    else return a.time < b.time;
}
bool cmpByTime(Car a, Car b)
{
    return a.time < b.time;
}
int main()
{
    int n, k, hh, mm, ss;
    scanf("%d%d%d", &n, &k);
    for(int i = 0; i < n; i++)
    {
        scanf("%s %d:%d:%d %s", all[i].id, &hh, &mm, &ss, all[i].status);
        all[i].time = timeToInt(hh, mm, ss);
    }
    sort(all, all + n, cmpByCarAndTime);
    int num = 0, maxtime = -1;
    for(int i = 0; i < n; i++)
    {
        if(!strcmp(all[i].id, all[i+1].id) &&
          !strcmp(all[i].status, "in") &&
          !strcmp(all[i + 1].status, "out"))
        {
            valid[num++] = all[i];
            valid[num++] = all[i + 1];
            int intime = all[i + 1].time - all[i].time;
            if(parkTime.count(all[i].id) == 0)
                parkTime[all[i].id] = 0;
            parkTime[all[i].id] += intime;
            maxtime = max(maxtime, parkTime[all[i].id]);
        }
    }
    sort(valid, valid + num, cmpByTime);
    int now = 0, carNum = 0;
    for(int i = 0; i < k; i++)
    {
        scanf("%d:%d:%d", &hh, &mm, &ss);
        int time = timeToInt(hh, mm, ss);
        while(now < num && valid[now].time <= time)
        {
            if(strcmp(valid[now].status, "in") == 0) carNum++;
            else carNum--;
            now++;
        }
        printf("%d\n", carNum);
    }
    map<string, int>::iterator it;
    for(it = parkTime.begin(); it != parkTime.end(); it++)
    {
        if(it->second == maxtime)
            printf("%s ", it->first.c_str());
    }
    printf("%02d:%02d:%02d", maxtime/3600, maxtime%3600/60, maxtime%60);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值