week 15

名人堂与代金券

对于在中国大学MOOC(http://www.icourse163.org/ )学习“数据结构”课程的学生,想要获得一张合格证书,总评成绩必须达到 60 分及以上,并且有另加福利:总评分在 [G, 100] 区间内者,可以得到 50 元 PAT 代金券;在 [60, G) 区间内者,可以得到 20 元PAT代金券。全国考点通用,一年有效。同时任课老师还会把总评成绩前 K 名的学生列入课程“名人堂”。本题就请你编写程序,帮助老师列出名人堂的学生,并统计一共发出了面值多少元的 PAT 代金券。

输入格式:

输入在第一行给出 3 个整数,分别是 N(不超过 10 000 的正整数,为学生总数)、G(在 (60,100) 区间内的整数,为题面中描述的代金券等级分界线)、K(不超过 100 且不超过 N 的正整数,为进入名人堂的最低名次)。接下来 N 行,每行给出一位学生的账号(长度不超过15位、不带空格的字符串)和总评成绩(区间 [0, 100] 内的整数),其间以空格分隔。题目保证没有重复的账号。

输出格式:

首先在一行中输出发出的 PAT 代金券的总面值。然后按总评成绩非升序输出进入名人堂的学生的名次、账号和成绩,其间以 1 个空格分隔。需要注意的是:成绩相同的学生享有并列的排名,排名并列时,按账号的字母序升序输出。

输入样例:

10 80 5
cy@zju.edu.cn 78
cy@pat-edu.com 87
1001@qq.com 65
uh-oh@163.com 96
test@126.com 39
anyone@qq.com 87
zoe@mit.edu 80
jack@ucla.edu 88
bob@cmu.edu 80
ken@163.com 70

输出样例:

360
1 uh-oh@163.com 96
2 jack@ucla.edu 88
3 anyone@qq.com 87
3 cy@pat-edu.com 87
5 bob@cmu.edu 80
5 zoe@mit.edu 80

 这题是一个比较简单的结构体排序的问题

定义一个结构体student,写入他的数据,按照题目的要求,成绩高的往前排,如果成绩相同,就按照账号的字典序来排序

所以我们就得把sort里面的cmp写一下

bool cmp(student b,student c){
    if(b.cz!=c.cz) return b.cz>c.cz;
    else return b.xh<c.xh;
}

 再看一眼,这题的输出还是有讲究的

它的排名我们要怎么输出出来

首先,我们定义一个记录排名的整数p,初始化为1;

然后每次出现相同的数字时,p都不会变,但在下一个不相同的数据里面,p会加上前面相同的人的个数,那我们再定义一个xt数据来记录相同的数据的数量,初始化为0,如果前后两个数据相同,xt++;不相同的化就是p++,p+=xt;加完xt后,要记得对xt进行初始化再使用

代码如下

#include <bits/stdc++.h>
using namespace std;
struct student{
    int cz;
    string xh;
    int qian=0;
    int paim=0;
}a[100005];
bool cmp(student b,student c){
    if(b.cz!=c.cz) return b.cz>c.cz;
    else return b.xh<c.xh;
}
int main(){
    int n,g,k;
    cin>>n>>g>>k;
    int sum=0;
    for(int i=0 ; i<n ; i++ ){
        cin>>a[i].xh>>a[i].cz;
        if(a[i].cz>=60&&a[i].cz<g) a[i].qian=20;
        else if(a[i].cz>=g&&a[i].cz<=100) a[i].qian=50;
        sum+=a[i].qian;
    }
    cout<<sum<<endl;
    sort(a,a+n,cmp);
    while(a[k].cz==a[k-1].cz){//计算多少人要输出
        k++;
    }
    int p=1;
    int xt=0;
    for(int i=0;i<k;i++){
        cout<<p<<' '<<a[i].xh<<' '<<a[i].cz<<endl;
        if(a[i+1].cz!=a[i].cz){
            p+=xt;
            p++;
            xt=0;//不要忘记重置xt的个数 
        }
        else xt++;
    }
    return 0;
}

排座位

布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。

输入格式:

输入第一行给出3个正整数:N(≤100),即前来参宴的宾客总人数,则这些人从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系,其中关系为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号。

这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。

输出格式:

对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but...;如果他们之间只有敌对关系,则输出No way

输入样例:

7 8 4
5 6 1
2 7 -1
1 3 1
3 4 1
6 7 -1
1 2 1
1 4 1
2 3 -1
3 4
5 7
2 3
7 2

输出样例:

No problem
OK
OK but...
No way

对于这题,是一个查并集的方法来实现

我也刚学会,写一下吧

对于一堆数据,我们把他们存到一个数组里面去

先初始化

数组a        1        2        3        4        5        6

                 1        2        3        4        5        6

一开始初始化为自己

再根据题目的意思进行站队

比如1把2,3交朋友 5和4,6交朋友

数组就变化了

a               1        2        3        4        5        6

                 1        1        1        5        5        5

那么这个数组就变成了1和5两个朋友圈,1和5是这个朋友圈的群主

2,3有共同朋友1;  4,6有共同朋友5;

a[2]=1;a[3]=1;a[4]=5;a[6]=5;

我们用find()函数来找到他们的朋友圈群主来看他们是不是朋友关系(朋友的朋友就是朋友)

int find(int x){

        if(a[x]!=x){//就是x有朋友了,且他不是这个朋友圈群主

                return x=find(a[x])//那么找到x的这个朋友,看看他是不是这个朋友圈群主

        }

        return x;//如果x是朋友圈群主,就把他返回

}

有的题目还得根据给定的信息来确定群主的更替

定义一个join函数

join(int x,int y){

        int fx=find(x);

        int fy=find(y);x和y两个群体的群主,如果是x的群主收买了y群的群主

        a[x]=fy;如果是两个群主合并了,那么任意一个都行

}

对于这题我们找到他们的朋友关系和敌人关系就行了

所以,我们还得记录一下他们是不是敌对关系

这个就比较简单了,敌人的敌人不一定是朋友,所以这个不用进行查并集,直接记录就行

用一个二维数组来记录g[a][b]表示a和b的敌对关系,不要忘记对g[b][a]进行赋值,他询问的两人没有先后顺序之分哦

最后按照题目要求输出就行了

#include <bits/stdc++.h>
using namespace std;
int parent[105];
int d[105][105];
int n;
int find(int x){
    if(parent[x]!=x) parent[x]=find(parent[x]);
    return parent[x];
}
int main(){
    int k,m;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        parent[i]=i;
    }
    while(m--){//宾客之间的关系
        int a,b,c;
        cin>>a>>b>>c;
        if(c==1) parent[find(a)]=find(b);//让ab当朋友
        else if(c==-1){
            d[a][b]=1;
            d[b][a]=1;//ab是敌人记录下来
        }
    }
    while(k--){
        int a,b;
        cin>>a>>b;
        if(d[a][b]==1){//两个人是敌人
            if(parent[find(a)]==find(b)){//又是朋友
                cout<<"OK but..."<<endl;
            }
            else cout<<"No way"<<endl;
        }
        else if(parent[find(a)]==find(b)){//两个人是朋友不是敌人
            cout<<"No problem"<<endl;
        }
        else cout<<"OK"<<endl;//既不是敌人也不是朋友
    }
    return 0;
}

包装机

一种自动包装机的结构如图 1 所示。首先机器中有 N 条轨道,放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时,活塞向左推动,将轨道尽头的一件物品推落筐中。当 0 号按钮被按下时,机械手将抓取筐顶部的一件物品,放到流水线上。图 2 显示了顺序按下按钮 3、2、3、0、1、2、0 后包装机的状态。

图1 自动包装机的结构

 

 

图 2 顺序按下按钮 3、2、3、0、1、2、0 后包装机的状态

一种特殊情况是,因为筐的容量是有限的,当筐已经满了,但仍然有某条轨道的按钮被按下时,系统应强制启动 0 号键,先从筐里抓出一件物品,再将对应轨道的物品推落。此外,如果轨道已经空了,再按对应的按钮不会发生任何事;同样的,如果筐是空的,按 0 号按钮也不会发生任何事。

现给定一系列按钮操作,请你依次列出流水线上的物品。

输入格式:

输入第一行给出 3 个正整数 N(≤100)、M(≤1000)和 Smax​(≤100),分别为轨道的条数(于是轨道从 1 到 N 编号)、每条轨道初始放置的物品数量、以及筐的最大容量。随后 N 行,每行给出 M 个英文大写字母,表示每条轨道的初始物品摆放。

最后一行给出一系列数字,顺序对应被按下的按钮编号,直到 −1 标志输入结束,这个数字不要处理。数字间以空格分隔。题目保证至少会取出一件物品放在流水线上。

输出格式:

在一行中顺序输出流水线上的物品,不得有任何空格。

输入样例:

3 4 4
GPLT
PATA
OMSA
3 2 3 0 1 2 0 2 2 0 -1

输出样例:

MATA

这题很明显就是一个stack的模拟运用,

对与这个筐(一个stack)和好几个轨道进行操作

轨道是先进先出,这不就符合我们队列的要求了

所以我们这题就直接用stack和queue来解决就行了

stack模拟筐,queue模拟轨道

 对于这题的情况,就这么几种,就是输入的值为0,大于0,-1

-1直接退出输入,比较好解决,当输入值为0 时:我们就对筐进行操作

如果筐不是空的,里面有东西,那我们就把筐最上面的东西取出来,放在流水线上(打印出来)

如果是空的我们就不进行任何操作

当输入值大于0时: 我们就得一边对筐进行操作,一边对轨道进行操作

如果输入的这个轨道不是空的,并且筐没有满,我们就从轨道上取一个物品下来,放到框里面

如果轨道不是空的,但是筐是满的,我们就把筐里面的东西放在流水线上,再从轨道上取一个东西下来

轨道如果是空的,那我们的操作就无效,不用再取操作

#include <bits/stdc++.h>
using namespace std;
int n,m,s;
queue<char> gd[105];
stack<char> st;
char a;
int main(){
    cin>>n>>m>>s;
    for(int i=1;i<=n;i++){//n个轨道
        for(int j=1;j<=m;j++){//每个轨道m个物品
            cin>>a;
            gd[i].push(a);
        }
    }
    while(true){
        int cz;
        cin>>cz;//输入操作
        if(cz==-1) break;//输入-1就结束
        if(cz==0&&!st.empty()){//输入的是0并且这个栈不是空的
            char b=st.top();//把顶端的物品取出放到流水线上
            printf("%c",b);
            st.pop();
        }
        if(cz>0&&st.size()<s&&gd[cz].size()){//cz>0说明是对轨道进行了操作
            st.push(gd[cz].front());//筐没有满,可以放下大小,并且轨道不是空的
            gd[cz].pop();
        }
        else if(cz>0&&st.size()==s&&gd[cz].size()){//筐满了,得拿出一件在放东西进去
            char b=st.top();//把顶端的物品取出放到流水线上
            printf("%c",b);
            st.pop();
            st.push(gd[cz].front());
            gd[cz].pop();
        }
    }
    return 0;
}

愿天下有情人都是失散多年的兄妹

呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?

输入格式:

输入第一行给出一个正整数N(2 ≤ N ≤104),随后N行,每行按以下格式给出一个人的信息:

本人ID 性别 父亲ID 母亲ID

其中ID是5位数字,每人不同;性别M代表男性、F代表女性。如果某人的父亲或母亲已经不可考,则相应的ID位置上标记为-1

接下来给出一个正整数K,随后K行,每行给出一对有情人的ID,其间以空格分隔。

注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

输出格式:

对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind;如果是异性并且关系出了五服,输出Yes;如果异性关系未出五服,输出No

输入样例:

24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011

输出样例:

Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No

这题有二叉树的感觉,一个人他就一个父亲和母亲,或者它的父母不可考,也就是没有父母

                                                        人

                                           父亲                     母亲

                                父亲          母亲         父亲        母亲

类似于这样的,但是我不会写树....所有看了别人的数组记录,再dfs

dfs(x,num)num用来记录代数,结束条件为dfs超过了四次,也就是他们的关系是五代之外,可以结婚,x就是这个人,我们再dfs(y,num)先对x进行dfs把他的五代内的亲戚标记一下,再对y进行dfs,如果他们两个人的五代之内有相同的亲戚,说明他们是失散多年的兄妹,呜呜呜

所有我们就得写一个vis数组来记录两个人的亲戚,对与他们的性别我们也得记录,因为封建思想,同性恋是不可能的,再来一个sexu数组记录性别;

对于他们关系的存图,我们可以用二维数组也可以用vector数组来记录;

先输入他们的关系,再对他们进行查户口

#include <bits/stdc++.h>
using namespace std;
int n,k;
vector <int> gx[100005];//存储关系
bool vis[100005];//
char sexu[100005];
bool flag;
void dfs(int x,int num){//num用来记录几代
    if(num>=4){//已经不在五代之内
        return ;
    }
    for(int i=0;i<gx[x].size();i++){//对x这个人的父母进行查询
        if(!vis[gx[x][i]]){
            vis[gx[x][i]]=1;//标记他的父母
            dfs(gx[x][i],num+1);
        }
        else flag=true;//如果这个人早就出先过了,说明这两个人在五代之内
    }
}
int main(){
    cin>>n;
    int r,fa,ma;
    for(int i=0;i<n;i++){
        cin>>r>>sexu[r]>>fa>>ma;
        if(fa!=-1){//如果他的父亲不可考,那我们就认为他没有父亲
            gx[r].push_back(fa);
            sexu[fa]='M';
        }
        if(ma!=-1){
            gx[r].push_back(ma);
            sexu[ma]='F';
        }
    }
    cin>>k;
    for(int i=0;i<k;i++){//进行k次询问
        int a,b;
        cin>>a>>b;
        if(sexu[a]==sexu[b]){
            cout<<"Never Mind"<<endl;//封建思想,同性不能结婚
        }
        else{
            memset(vis,0,sizeof(vis));//对vis数组进行初始化
            vis[a]=1;
            vis[b]=1;
            flag=false;
            dfs(a,0);//先找出x的所有五代内的亲戚
            dfs(b,0);//再找y的五代内的亲戚,如果有重复就说明两个人是近亲结婚
            if(flag){
                cout<<"No"<<endl;
            }
            else cout<<"Yes"<<endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值