day02:函数&递归&结构体&sort(a,a+n,cmp);

day02:函数&递归&结构体&sort(a,a+n,cmp);

函数:其实就是将一个方法进行封装,方便下次调用,主要注意传入参数与返回参数

#include<cmath> 
floor(3.14) = 3 向下取整 
ceil(3.14) = 4  向上取整
abs(-1) = 1     取绝对值
pow(2,3)=2*2*2 = 8
pow(a,n)        n个a的乘积 

递归:就是按照某一个规则进行套娃的游戏,依赖于函数的嵌套,同时递归需要注意两个点:

  1. 递归出口:什么时候游戏结束,或者破坏了游戏规则

  2. 递归条件:什么继续下次游戏,注意看是否需要打标记

如:给出一个数n,递归输出1-n

很容易对吧!直接for就可以,但是现在规定你必须用递归来做,怎么办呢?
首先:确定一个递归表达式 dfs(int i){} // i 表示递归层数,并用作结果输出
找到递归出口:当输出结果为n,也就是i>n就停止
如果没有找到递归出口,就继续递归i+1

#include<bits/stdc++.h>
using namespace std;
int n;
void dfs(int i){
    if(i>n)	return;//递归出口
    printf("%d ", i);
    dfs(i+1); //继续递归
}
int main(){
    cin>>n; dfs(1);
    return 0;
}

结构体:

struct T{
    string name;  //属性
    int age;
    int score1,score2,score3;
    int sum(){    //行为
        return score1+score2+score3;
    }
}stu[100];

我们可以将它(T)看做一类人,而stu[100];就是这一类人中的100个人,他们具有相似的属性(name,age,score)和行为(sum())

结构体一般在泛型排序结合贪心的题型上使用,如:

给出5个人的信息(包括姓名,年龄,三门学科分数),现在让你按照三门学科总分进行降序排序,如果总分相同则年龄小的在前面

#include<bits/stdc++.h>
using namespace std;
const int N=100, n=5;
struct T{
    string name;
    int age;
    int score1,score2, score3;
    int sum(){
        return score1+score2+score3; 
    }
}stu[N];

//按照总分大小排序,如果总分相同按照年龄小大排序 
bool cmp(T a, T b){
    if(a.sum()!=b.sum()) return a.sum()>b.sum();
    return a.age<b.age;
}

/*输入样例: 
a 11 100 100 100
b 22 80  90  90
c 33 90  90  90
d 44 80  80  80
e 55 90  80  80
*/
int main(){
    for(int i=0; i<n; i++){
	cin>>stu[i].name>>stu[i].age>>stu[i].score1>>stu[i].score2>>stu[i].score3;
    }
    sort(stu, stu+n, cmp);
    for(int i=0; i<n; i++){
        cout<<stu[i].name<<" "<<stu[i].age<<" "<<stu[i].sum()<<endl;
    }return 0;
}

1. B2134 质数的和与积

【题目描述】两个质数的和是 S,它们的积最大是多少?

输入格式:一个不大于 10000 的正整数 S,为两个质数的和。

输出格式:一个整数,为两个质数的最大乘积。数据保证有解。

输入样例:50

输出样例:589

题解:

#include<bits/stdc++.h>
using namespace std;
bool isPrime(int n) {
    if(n<2) return false;
    for(int i=2; i*i<=n; i++)
        if(n%i==0) return false;
    return true;
}
int main() {
    int n,max=0;  cin>>n;
    for(int i=2; i<=n; i++) {
        if(isPrime(i) && isPrime(n-i)) {
            int num = i*(n-i);
            if(max<num) max = num;//最大值
        }
    }
    cout<<max; return 0;
}

2. P1255 数楼梯

【题目描述】楼梯有 N阶,上楼可以一步上一阶,也可以一步上二阶。

编一个程序,计算共有多少种不同的走法。

输入格式:一个数字,楼梯数。

输出格式:输出走的方式总数。

输入样例:4

输出样例:5

说明/提示:对于60% 的数据,N≤50;对于100% 的数据,N≤5000。

题解:这道题目需要使用高精度,所以按照long long能过40分就OK。

#include<iostream>
using namespace std;
long long dfs(int num){// 楼梯数 
    if(num==1) return 1;
    else if(num==2) return 2;
    return dfs(num-1)+dfs(num-2);
    //dfs(i-1) --> 走一阶楼梯
}
int main(){
    int n=4; cin>>n;
    cout<<dfs(n);
    return 0;
} 

3. P1706 全排列问题

【题目描述】按照字典序输出自然数 11 到 nn 所有不重复的排列,即 nn 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式:一个整数 n(1≤n≤9)

输出格式:由 1∼n 组成的所有不重复的数字序列,每行一个序列。每个数字保留 5 个场宽

输入样例:3

输出样例:

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

题解:

#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int n=3;
int vis[N], a[N];

//递归选择数据个数 
void dfs(int k){
    if(k>n){
        for(int i=1; i<=n; i++){
            cout<<setw(5)<<a[i];//输出控制5个宽度 
        }cout<<endl;
        return;
    }
    for(int i=1; i<=n; i++){
        if(vis[i]==0){
            vis[i]=1;
            a[k]=i;
            dfs(k+1);
            vis[i]=0;//回溯到上一级 
        }
    }
}
int main(){
    cin>>n;    dfs(1);
    return 0;
}

4. P5740 【深基7.例9】最厉害的学生

【题目描述】现有 N(N≤1000) 名同学参加了期末考试,并且获得了每名同学的信息:姓名(不超过 8 个字符的字符串,没有空格)、语文、数学、英语成绩(均为不超过 150 的自然数)。总分最高的学生就是最厉害的,请输出最厉害的学生各项信息(姓名、各科成绩)。如果有多个总分相同的学生,输出靠前的那位。

输入格式:先输入数字 n,表示有n个学生,再输入n行,每行包含学生姓名,语文、数学、英语成绩

输出格式:最厉害的学生各项信息(姓名、语文、数学、英语成绩)

输入样例:

3
senpai 114 51 4
lxl 114 10 23
fafa 51 42 60

输出样例:

senpai 114 51 4

题解:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3;
struct T{
    string name;
    int a,b,c,id;
    int sum(){
        return a+b+c;
    }
}stu[N];

bool cmp(T a, T b){
    if(a.sum()!=b.sum()) return a.sum() > b.sum();//按照总分降序排序
    return a.id < b.id; //总分相同,按照学号升序排序
}
int main() {
    int n; cin>>n;
    for(int i=0; i<n; i++){
        stu[i].id = i;
        cin>>stu[i].name>>stu[i].a>>stu[i].b>>stu[i].c;
    }
    sort(stu, stu+n, cmp);//自定义排序方式

    int i=0;
    cout<<stu[i].name<<" "<<stu[i].a<<" "<<stu[i].b<<" "<<stu[i].c;
    return 0;
}

--------------------------------------
#include<bits/stdc++.h>//其实这道题目不用结构体也能做-舒同学的解法
using namespace std;
string a[1001];
int b[1001][4],sum,maxb,maxa,n;//全局变量默认初始化0 
int main() {
    cin>>n;
    for(int i=0; i<n; i++) {
        cin>>a[i]>>b[i][1]>>b[i][2]>>b[i][3];//信息输入 
        sum=b[i][1]+b[i][2]+b[i][3];//总分求和 
        if(maxb<sum) {
            maxb=sum;
            maxa=i;
        }
    }
    cout<<a[maxa]<<" "<<b[maxa][1]<<" "<<b[maxa][2]<<" "<<b[maxa][3];
    return 0;
}

5. P5742 【深基7.例11】评等级

【题目描述】现有 N(N≤1000) 名同学,每名同学需要设计一个结构体记录以下信息:学号(不超过 100000 的正整数)、学业成绩和素质拓展成绩(分别是 0 到 100 的整数)、综合分数(实数)。每行读入同学的姓名、学业成绩和素质拓展成绩,并且计算综合分数(分别按照 70% 和 30% 权重累加),存入结构体中。还需要在结构体中定义一个成员函数,返回该结构体对象的学业成绩和素质拓展成绩的总分。

然后需要设计一个函数,其参数是一个学生结构体对象,判断该学生是否“优秀”。优秀的定义是学业和素质拓展成绩总分大于140 分,且综合分数不小于 80 分。

输入格式:

第一行一个整数 N,接下来 N 行,每行 3 个整数,依次代表学号、学业成绩和素质拓展成绩。

输出格式:N 行,如果第 i 名学生是优秀的,输出 Excellent,否则输出 Not excellent

输入样例:

4
1223 95 59
1224 50 7
1473 32 45
1556 86 99

输出样例:

Excellent
Not excellent
Not excellent
Excellent

题解:

#include<bits/stdc++.h>
using namespace std;
struct T{
    int id;
    int s1,s2;//学业成绩和素质拓展成绩
    double s3;//综合分数(实数)
    double sum1(){//学业成绩和素质拓展成绩的总分
        return s1+s2;
    }
}stu[1000];

int main(){
    int n; cin>>n;
    for(int i=0; i<n; i++){
        cin>>stu[i].id>>stu[i].s1>>stu[i].s2;
        stu[i].s3=0.7*stu[i].s1+0.3*stu[i].s2;
    }
    for(int i=0; i<n; i++){
        if(stu[i].sum1()>140 && stu[i].s3>=80){//优生条件
            cout<<"Excellent"<<endl;
        }else{
            cout<<"Not Excellent"<<endl;
        }
    } return 0;
}

6. P1093 [NOIP2007 普及组] 奖学金

【题目描述】某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。期末,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学 排在前面,这样,每个学生的排序是唯一确定的。

任务:先根据输入的3门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名名学生的学号和总分。注意,在前5名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。例如,在某个正确答案中,如果前两行的输出数据(每行输出两个数:学号、总分) 是:

7 279
5 279

这两行数据的含义是:总分最高的两个同学的学号依次是7号、5号。这两名同学的总分都是 279 (总分等于输入的语文、数学、英语三科成绩之和) ,但学号为7的学生语文成绩更高一些。如果你的前两名的输出数据是:

5 279
7 279

则按输出错误处理,不能得分。

输入格式:

共n+1行
第1行为一个正整数n(n≤300),表示该校参加评选的学生人数。
第2到n+1行,每行有3个用空格隔开的数字,每个数字都在0到100之间。
第j行的3个数字依次表示学号为j-1的学生的语文、数学、英语的成绩。
每个学生的学号按照输入顺序编号为1~n(恰好是输入数据的行号减1)。
所给的数据都是正确的,不必检验。

输出格式:共5行,每行是两个用空格隔开的正整数,依次表示前5名学生的学号和总分。

输入样例:

6
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98

输出样例:

6 265
4 264
3 258
2 244
1 237

题解:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=310;
struct T{
    int s1,s2,s3;//语文,数学,英语成绩
    int id;   //学号 
    int sum(){//总分 
        return s1+s2+s3;
    } 
}stu[N]; 

bool cmp(T a, T b){
    if(a.sum()!=b.sum()) return a.sum()>b.sum();//总分降序排列 
    if(a.s1!=b.s1) return a.s1>b.s1;//语文成绩降序排列 
    return a.id<b.id;//学号升序排列 
} 

int main() {
    int n; cin>>n;
    for(int i=0; i<n; i++){
        cin>>stu[i].s1>>stu[i].s2>>stu[i].s3;
        stu[i].id = i+1;//学号 
    } 
    sort(stu, stu+n, cmp);//自定义排序 
    for(int i=0; i<5; i++){//前5名 
        cout<<stu[i].id<<" "<<stu[i].sum()<<endl;
    } return 0;
}

7. P1104 生日

【题目描述】cjf 君想调查学校OI组每个同学的生日,并按照从大到小的顺序排序。

输入格式:有2行,第1行为OI组总人数n,第2行至第n+1行分别是每人的姓名s、出生年y、月m、日d

输出格式:有n行,即n个生日从大到小同学的姓名(如果有两个同学生日相同,输入靠后的同学先输出)

输入样例:

3
Yangchu 1992 4 23
Qiujingya 1993 10 13
Luowen 1991 8 1

输出样例:

Luowen
Yangchu
Qiujingya

数据范围:1<n<100,length(s)<20

题解:

#include<iostream>
#include<algorithm>
using namespace std;
struct T{
    string name;
    int y,m,d;//year,month,day
    int id;   //输入先后顺序 
}stu[110];

bool cmp(T a, T b){
    if(a.y!=b.y) return a.y<b.y;//如果年份不同,按年份升序排序 
    if(a.m!=b.y) return a.m<b.m;//如果月份不同,按月份升序排序 
    if(a.d!=b.d) return a.d<b.d;//如果天数不同,按天数升序排序 
    return a.id>b.id; //按输入顺序,逆序排序 
} 
int main() {
    int n; cin>>n;
    for(int i=0; i<n; i++){
        cin>>stu[i].name>>stu[i].y>>stu[i].m>>stu[i].d;
        stu[i].id = i; 
    }
    sort(stu, stu+n, cmp);//自定义排序规则 
    for(int i=0; i<n; i++){
        cout<<stu[i].name<<endl;
    } return 0;
}

8. P1068 [NOIP2009 普及组] 分数线划定

【题目描述】世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,AA市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%划定,即如果计划录取m名志愿者,则面试分数线为排名第m×150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。

现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。

输入格式:
第一行,两个整数 n,m(5≤n≤5000,3≤m≤n),中间用一个空格隔开,其中 n表示报名参加笔试的选手总数,m表示计划录取的志愿者人数。输入数据保证 m×150%向下取整后小于等于 n。

第二行到第 n+1 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号 k(1000≤k≤9999)和该选手的笔试成绩 s(1≤s≤100)。数据保证选手的报名号各不相同。

输出格式:
第一行,有2个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。

从第二行开始,每行包含2个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。

输入样例:

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 

题解:

#include<bits/stdc++.h>
using namespace std;
const int N=1e4;
struct T{
    int k,s;
}stu[N];

bool cmp(T a, T b){
    if(a.s!=b.s) return a.s>b.s;//按成绩降序排列 
    return a.k<b.k;//按成绩升序排列 
}

int main(){
    int n,m; cin>>n>>m;
    int num=floor(m*1.5);//参与面试的人数 
    for(int i=1; i<=n; i++){
        cin>>stu[i].k>>stu[i].s;
    }
    sort(stu+1, stu+n+1, cmp);
    int score=0, ans=0;//最后进入面试的分数,人数 
    for(int i=1; i<=n; i++){
        if(i<=num || stu[i].s==score){
            ans++;
            score=stu[i].s;
        }else{
            break;
        }
    }
    cout<<score<<" "<<ans<<endl;
    for(int i=1; i<=ans; i++){
        cout<<stu[i].k<<" "<<stu[i].s<<endl;
    }return 0;
}

9. P1051 [NOIP2005 提高组] 谁拿了最多奖学金

【题目描述】 某校的惯例是在每学期的期末考试之后发放奖学金。发放的奖学金共有五种,获取的条件各自不同:

院士奖学金,每人8000元,期末平均成绩高于80分(>80),并且在本学期内发表1篇或1篇以上论文的学生均可获得;
五四奖学金,每人4000元,期末平均成绩高于85分(>85),并且班级评议成绩高于80分(>80)的学生均可获得;
成绩优秀奖,每人2000元,期末平均成绩高于90分(>90)的学生均可获得;
西部奖学金,每人1000元,期末平均成绩高于85分(>85)的西部省份学生均可获得;
班级贡献奖,每人850元,班级评议成绩高于80分(>80)的学生干部均可获得;

只要符合条件就可以得奖,每项奖学金的获奖人数没有限制,每名学生也可以同时获得多项奖学金。例如姚林的期末平均成绩是87分,班级评议成绩82分,同时他还是一位学生干部,那么他可以同时获得五四奖学金和班级贡献奖,奖金总数是4850元。

现在给出若干学生的相关数据,请计算哪些同学获得的奖金总数最高(假设总有同学能满足获得奖学金的条件)。

输入格式:
第一行是1个整数N(1≤N≤100),表示学生的总数。

接下来的NN行每行是一位学生的数据,从左向右依次是姓名,期末平均成绩,班级评议成绩,是否是学生干部,是否是西部省份学生,以及发表的论文数。姓名是由大小写英文字母组成的长度不超过20的字符串(不含空格);期末平均成绩和班级评议成绩都是0到100之间的整数(包括0和100);是否是学生干部和是否是西部省份学生分别用1个字符表示,Y表示是,N表示不是;发表的论文数是0到1010的整数(包括0和10)。每两个相邻数据项之间用一个空格分隔。

输出格式:
包括3行,第1行是获得最多奖金的学生的姓名。
第2行是这名学生获得的奖金总数。如果有两位或两位以上的学生获得的奖金最多,输出他们之中在输入文件中出现最早的学生的姓名。
第3行是这N个学生获得的奖学金的总数。

输入样例:

4
YaoLin 87 82 Y N 0
ChenRuiyi 88 78 N Y 1
LiXin 92 88 N N 0
ZhangQin 83 87 Y N 1

输出样例:

ChenRuiyi
9000
28700

题解:这道题就是使用结构体来排序,并且多了一下判断条件,需要注意细节

#include<bits/stdc++.h>
using namespace std;
const int N=1e2+5; //定义常量N
struct T{
    int id;
    string name;
    int score1,score2,num;
    char flag1,flag2;
    int money(){
        int sum=0;
        if(score1>80 && num>=1) sum+=8000;
        if(score1>85  && score2>80) sum+= 4000;
        if(score1>90) sum += 2000;
        if(score1>85  && flag2=='Y') sum += 1000;
        if(score2>80 && flag1=='Y') sum += 850;
        return sum;
    }
}stu[N];
 
bool cmp(T a, T b){//自定义排序规则
    if(a.money() !=b.money()){
        return a.money() > b.money();//获得奖学金最多的同学在前
    }
    return a.id < b.id;//按学号升序排序
}

int main(){
    int n; cin>>n;
    for(int i=0; i<n; i++){
        cin>>stu[i].name>>stu[i].score1
            >>stu[i].score2>>stu[i].flag1
            >>stu[i].flag2>>stu[i].num;
        stu[i].id = i;
    }
    sort(stu, stu+n, cmp);//自定义排序,注意下标
    int sum=0;
    for(int i=0; i<n; i++){
        sum += stu[i].money();//奖学金总数
    }
    cout<<stu[0].name<<endl<<stu[0].money()<<endl;
    cout<<sum<<endl; return 0;
}
posted @ 2021-08-01 07:20  HelloHeBin  阅读(468)  评论(0编辑  收藏  举报