帮牛牛找工作

牛牛找工作这个题目是2019年网易校招编程真题。本人菜鸟,解这个题解了一天,没有成果,也不知道哪里出了错。后来干脆去找已经成功提交的代码。对着别人的代码一行一行码。然后自己简单修改一下。现在回顾反思一下解题思路。

题目描述

为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。牛牛的小伙伴太多了,于是他只好把这个任务交给了你。

输入描述:

每个输入包含一个测试用例。

每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)

接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)

接下来的一行包含M个正整数,分别表示M个小伙伴的能力值Ai(Ai<=1000000000)

保证不存在两项工作的报酬相同。

输出描述:

对于每个小伙伴,在单独的一行输出一个正整数表示他能得到的最高报酬。一个工作可以被多个人选择。

示例1

输入

3 3

1 100

10 1000

1000000000 1001

9 10 1000000000

输出

100

1000

1001

本题的解题思路分为5步:

1. 按格式读取工作数据和需要找工作的人员数量;

2.对工作数据按照难度进行排序;

3.重新分配每个工作难度对应的薪水;

4.读取员工的能力,并找到适合其能力的最高薪水;

5.输出每个员工的最高薪水。

接下来我一步一步地对每一步的细节进行解释说明。

1. 按格式读取工作数据和需要找工作的人员数量;

先看输入描述:

每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)
接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)

第一行数据有两个正整数,分别为工作种类N和找工作的人数M。根据M和N的大小条件限制。可以用int (32位机器上可以表示的数据范围为2^-31~(2^31-1)型的数据表示。有了工作的数量N,就可以将工作数据读取到内存中。这里数据形式使用了结构体,工作结构体包含了两个成员,第一个成员是difficulty表示工作难度,第二个成员salary表示薪水数量。二者都采用整型定义。在这里使用了malloc函数开辟了可以容纳工作数据的一个地址空间。这个空间里用于存放工作数据结构体。首地址交给了joblist结构体指针变量。然后以此按照给定格式将工作数据存到结构体数组中去。这种使用malloc开辟空间的做法减少了空间浪费,需要多少,开辟多少。

2.对工作数据按照难度进行排序

拿到了工作数据之后,为了方便后来的比较。按照难度,将工作数据排个序。容易的在低地址,难的在高地址。这里顺序的升序降序无所谓,只是代码表示的不同。本文使用了从低到高的排序方法。这里使用了qsort库函数。

qsort函数有四个参数:1.排序后存放数据的首地址,一般放一个数组的首地址;2.需要排序元素的数量,对数组中所有的元素排序,放上数组元素的数量即可;3.被排序的各个元素所占用的字节大小;4 指向函数的指针,用于确定排序的顺序(需要用户自定义一个比较函数)这个函数的类型和形参是固定的。函数体可以根据需要自定义。

int comp(const void *a,const void *b)
{
   
job *a1=(job *)a,*a2=(job *)b;
    if
(a1->difficulty>a2->difficulty)
       
return 1;
    else if
(a1->difficulty==a2->difficulty)
       
return 0;
    else
        return
-1;
}

本例定义如上,输入参数作为工作数据的结构体指针。比较两个结构体指针指向的结构体中difficulty即工作难度的大小。当a1所指向的结构体成员difficulty大于a2所指向的结构体成员difficulty时,返回1;两者相等时,返回0;a1所指向的结构体成员difficulty小于a2所指向的结构体成员difficulty时,返回-1。这是升序排列。反之,则为降序排列。

3.重新分配每个工作难度对应的薪水;

这个思路是这样的。输入的工作数据中,有可能出现工作难度很大,但是薪水比较低的情况。这种工作往往不是最好的工作。所以,需要将工作难度和薪水相匹配。如果工作A的工作难度大于工作B的难度,那么工作A的薪水也应当大于等于工作B。由于排序中,工作难度是递增的,所以,薪水是不减的。工作难度和薪水相匹配之后,有利于依据工作能力来寻找最高的薪水。

4.读取员工的能力,并找到适合其能力的最高薪水;

这是关键的一步。这里的思路决定了整个程序的时间复杂度。这里使用了二分法。

每获取一个人的能力水平之后。首先定义起点位置start=0和终点位置end=N。计算出中间点mid=(start+end)/2的难度水平。此时有三种情况,可以分别处理。

(1).此人的能力恰好能胜任mid这一位置的难度,不能胜任下一位置的难度。由于薪水是不减的,所以,此人能力范围能所能获得的最高薪水为mid位置的薪水。跳出此次寻找。输出其最高薪水。进行下一个人的寻找阶段。

(2).此人能力小于中间点mid位置的工作难度。此时起点不变,将mid-1作为终点。更新mid。

(3).此人能力大于中间点mid位置的工作难度。此时终点不变,将mid+1作为起点。更新mid。

当起点位置大于终点位置的时候,此人的能力值不等于任何一个工作的难度。介于mid左右两个工作难度之间。跳出此次寻找。

5.输出每个员工的最高薪水。

每一次寻找结束时。有两种情况结束寻找(1).此人的能力等于mid位置的工作难度;(2)。此人的能力在mid-1到mid+1两个工作的难度之间。所以,对其能力与mid位置的工作难度比较之后,即可判断此人所能获得的最大薪水是mid位置的薪水还是mid-1位置的薪水。

 

完整源码如下:

#include <stdio.h>
#include <stdlib.h>
int comp(const void* _a , const void* _b);
typedef struct
_job
{
   
int difficulty;
    int
salary;
}job;

int
main() {
    
int  N,M,start=0,end,mid;//N种工作,M个员工
    
int   temp=0;
    
/****************读取工作数据****************/
   
scanf("%d %d",&N,&M);
   
job *joblist=(job*)malloc(sizeof(job)*N);
    for
( int  i = 0; i < N; ++i) {
        scanf(
"%d %d",&joblist[i].difficulty,&joblist[i].salary);
   
}
   
/******按照工作难度排序,从容易到复杂********/
   
qsort(joblist,N,sizeof( job ),comp);
   
/*****对每个工作难度对应的薪水重新分配*******/
   
temp=joblist[0].salary;
    for
(int i = 1; i < N; ++i) {
       
if (joblist[i].salary<temp)
        {
            joblist[i].
salary=temp;
       
} else
       
{
            temp=joblist[i].
salary;
       
}
    }

   
/*****读取员工的能力并找到适合其能力的最高薪水*****/
   
for (int j = 0; j < M; ++j)
    {
        scanf(
"%d",&temp);
        for
(start=0,end=N-1; start <=end; ) {
            mid=(start+end)/
2;
            if
((temp==joblist[mid].difficulty)&&(temp<joblist[mid+1].difficulty))

{
               
break;
           
} else if (temp<joblist[mid].difficulty)
            {
                end=mid-
1;
           
} else
           
{
                start=mid+
1;
           
}
        }
       
/***输出每个员工的最高薪水********/
       
if (temp>=joblist[mid].difficulty)
        {
            printf(
"%d\n",joblist[mid].salary);
       
} else
       
{
            printf(
"%d\n",joblist[mid-1].salary);
       
}
    }
   
return 0;
}

int comp(const void *a,const void *b)
{
   
job *a1=(job *)a,*a2=(job *)b;
    if
(a1->difficulty>a2->difficulty)
       
return 1;
    else if
(a1->difficulty==a2->difficulty)
       
return 0;
    else
        return
-1;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值