HHU2017杂题训练(一)

来自zyyyyy的留言:久远的浙大机试题...

A - 找出直系亲属

 

如果A,B是C的父母亲,则A,B是C的parent,C是A,B的child,如果A,B是C的(外)祖父,祖母,则A,B是C的grandparent,C是A,B的grandchild,如果A,B是C的(外)曾祖父,曾祖母,则A,B是C的great-grandparent,C是A,B的great-grandchild,之后再多一辈,则在关系上加一个great-。
Input
输入包含多组测试用例,每组用例首先包含2个整数n(0<=n<=26)和m(0<m<50), 分别表示有n个亲属关系和m个问题, 然后接下来是n行的形式如ABC的字符串,表示A的父母亲分别是B和C,如果A的父母亲信息不全,则用-代替,例如A-C,再然后是m行形式如FA的字符串,表示询问F和A的关系。 
当n和m为0时结束输入。
Output
如果询问的2个人是直系亲属,请按题目描述输出2者的关系,如果没有直系关系,请输出-。 
具体含义和输出格式参见样例.
Sample Input
3 2
ABC
CDE
EFG
FA
BE
0 0
Sample Output
great-grandparent
-

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+10;
struct unit{
    int ch;
    unit *father;
    unit *mother;
    unit *son;
    unit(): father(NULL),mother(NULL),son(NULL){};
}*save[maxn];
unit *newUnit(){
    return new unit();
}
char in[10];
bool vis[maxn];
int res;
void findRelation(int x,int target,int sum){
    if(vis[x]||vis[target]){
        return;
    }
    if(x==target){
        res = sum;
        return;
    }
    if(sum>=0&&(save[x]->mother!=NULL||save[x]->father!=NULL)){
        if(save[x]->mother!=NULL){
            findRelation(save[x]->mother->ch, target, sum+1);
        }
        if(save[x]->father!=NULL){
            findRelation(save[x]->father->ch, target, sum+1);
        }
    }
    if(sum<=0&&save[x]->son!=NULL){
        findRelation(save[x]->son->ch, target, sum-1);
    }
}
int main(){
    int n,m,i,j;
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0){
            return 0;
        }
        getchar();
        memset(vis, true, sizeof(vis));
        for(i=1;i<=n;i++){
            scanf("%s",in);
            getchar();
            for(j=0;j<3;j++){
                if(in[j]!='-'){
                    if(vis[in[j]]){save[in[j]] = newUnit();vis[in[j]]=false;}
                    save[in[j]]->ch = in[j];
                }
            }
            if(in[0]!='-'&&in[1]!='-'){
                save[in[0]]->father = save[in[1]];
                save[in[1]]->son = save[in[0]];
            }
            if(in[0]!='-'&&in[2]!='-'){
                save[in[0]]->mother = save[in[2]];
                save[in[2]]->son = save[in[0]];
            }
        }
        for(i=1;i<=m;i++){
            scanf("%s",in);
            getchar();
            res = inf;
            findRelation(in[0], in[1],0);
            if(res==inf){
                printf("-\n");
                continue;
            }else if(abs(res)>=2){
                for(j=abs(res)-2;j>0;j--){
                    printf("great-");
                }
                printf("grand");
            }
            if(res>0){
                printf("child\n");
            }else{
                printf("parent\n");
            }
        }
    }
    return 0;
}

B - 最短路径问题

 

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
Input
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点。n和m为0时输入结束。 
(1<n<=1000, 0<m<100000, s != t)
Output
输出 一行有两个数, 最短距离及其花费。
Sample Input
3 2
1 2 5 6
2 3 4 5
1 3
0 0
Sample Output
9 11
Hint
注意处理重边!

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
#define INF 0x3f3f3f
const int maxn = 1010;
struct unit{
    int to;
    int dis;
    int cost;
    unit(int a,int b,int c): to(a),dis(b),cost(c){}
};
vector<unit> E[maxn];
int n,m,s,e;
pair<int,int> d[maxn];
void init(){
    int i;
    for(i=1;i<=n;i++){
        E[i].clear();
    }
    for(i=1;i<=n;i++){
        d[i].first = INF;
        d[i].second = INF;
    }
}
bool spfa(){
    priority_queue<pair<int, int> > que;
    d[s].first = 0;
    d[s].second = 0;
    que.push(make_pair(-d[s].first, s));
    while(!que.empty()){
        int q = que.top().second;
        if(q==e){
            break;
        }
        que.pop();
        for(int i=0;i<E[q].size();i++){
            int v = E[q][i].to;
            if(d[v].first>=d[q].first+E[q][i].dis){
                if(d[v].first>d[q].first+E[q][i].dis){
                    d[v].first = d[q].first+E[q][i].dis;
                    d[v].second = d[q].second + E[q][i].cost;
                    que.push(make_pair(-d[v].first, v));
                }else{
                    if(d[v].second>d[q].second+E[q][i].cost){
                        d[v].first = d[q].first+E[q][i].dis;
                        d[v].second = d[q].second + E[q][i].cost;
                        que.push(make_pair(-d[v].first, v));
                    }
                }
            }
        }
    }
    if(d[e].first==INF){
        return false;
    }else{
        return true;
    }
}
int main(){
    int i;
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0){
            return 0;
        }
        int a,b,D,p;
        init();
        for(i=0;i<m;i++){
            scanf("%d%d%d%d",&a,&b,&D,&p);
            E[a].push_back(unit(b,D,p));
            E[b].push_back(unit(a,D,p));
        }
        scanf("%d%d",&s,&e);
        if(spfa()){
            printf("%d %d\n",d[e].first,d[e].second);
        }else{
            printf("-1\n");
        }
    }
    
    return 0;
}

C - 二叉搜索树

 

判断两序列是否为同一二叉搜索树序列
Input
开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束。 
接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树。 
接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树。
Output
如果序列相同则输出YES,否则输出NO 
Sample Input
2
567432
543267
576342
0
Sample Output
YES
NO

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
int sample[2500];
bool vis1[2500];
int another[2500];
bool vis2[2500];
char in[1000];
bool judge(){
    int i;
    for(i=1;i<2400;i++){
        if(another[i]!=sample[i]){
            return false;
        }
    }
    return true;
}
int main(){
    int n,i,j;
    while(~scanf("%d",&n)&&n){
        getchar();
        scanf("%s",in);
        getchar();
        int len = strlen(in);
        memset(sample,0,sizeof(sample));
        memset(vis1, true, sizeof(vis1));
        int index;
        for(i=0;i<len;i++){
            index = 1;
            while(!vis1[index]){
                if(in[i]-'0'<=sample[index]){
                    index *= 2;
                }else{
                    index = index*2+1;
                }
            }
            sample[index] = in[i]-'0';
            vis1[index] = false;
        }
        for(int j=1;j<=n;j++){
            memset(vis2, true, sizeof(vis2));
            memset(another, 0, sizeof(another));
            scanf("%s",in);
            getchar();
            len = strlen(in);
            for(i=0;i<len;i++){
                index = 1;
                while(!vis2[index]){
                    if(in[i]-'0'<=another[index]){
                        index *= 2;
                    }else{
                        index = index*2+1;
                    }
                }
                another[index] = in[i]-'0';
                vis2[index] = false;
            }
            if(judge()){
                printf("YES\n");
            }else{
                printf("NO\n");
            }
        }
    }
    return 0;
}

D - 开门人和关门人

 

每天第一个到机房的人要把门打开,最后一个离开的人要把门关好。现有一堆杂乱的机房签 
到、签离记录,请根据记录找出当天开门和关门的人。 
Input
测试输入的第一行给出记录的总天数N ( > 0 )。下面列出了N天的记录。 
每天的记录在第一行给出记录的条目数M ( > 0 ),下面是M行,每行的格式为 

证件号码 签到时间 签离时间 

其中时间按“小时:分钟:秒钟”(各占2位)给出,证件号码是长度不超过15的字符串。 
Output
对每一天的记录输出1行,即当天开门和关门人的证件号码,中间用1空格分隔。 
注意:在裁判的标准测试输入中,所有记录保证完整,每个人的签到时间在签离时间之前, 
且没有多人同时签到或者签离的情况。 
Sample Input
3
1
ME3021112225321 00:00:00 23:59:59
2
EE301218 08:05:35 20:56:35
MA301134 12:35:45 21:40:42
3
CS301111 15:30:28 17:00:10
SC3021234 08:00:00 11:25:25
CS301133 21:45:00 21:58:40
Sample Output
ME3021112225321 ME3021112225321
EE301218 MA301134
SC3021234 CS301133

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 100;
char name[maxn],in[maxn],out[maxn];
char firstIn[maxn],lastOut[maxn];
int compare(int x1,int y1,int z1,int x2,int y2,int z2){
    if(x1==x2){
        if(y1==y2){
            if(z1==z2){
                return 0;
            }else if(z1>z2){
                return 1;
            }else{
                return -1;
            }
        }else{
            if(y1>y2){
                return 1;
            }else{
                return -1;
            }
        }
    }else{
        if(x1>x2){
            return 1;
        }else{
            return -1;
        }
    }
}
int main(){
    int t,n,i,j,a,b,c;
    scanf("%d",&t);
    getchar();
    while(t--){
        scanf("%d",&n);
        scanf("%s %s %s",name,in,out);
        getchar();
        strcpy(firstIn, name);
        strcpy(lastOut, name);
        int xi,yi,zi,xo,yo,zo;
        sscanf(in, "%d:%d:%d", &xi,&yi,&zi);
        sscanf(out, "%d:%d:%d", &xo,&yo,&zo);
        for(i=2;i<=n;i++){
            scanf("%s %s %s",name,in,out);
            sscanf(in, "%d:%d:%d", &a,&b,&c);
            if(compare(xi, yi, zi, a, b, c)>0){
                xi = a, yi = b, zi = c;
                strcpy(firstIn, name);
            }
            sscanf(out, "%d:%d:%d", &a,&b,&c);
            if(compare(xo, yo, zo, a, b, c)<0){
                xo = a, yo = b, zo = c;
                strcpy(lastOut, name);
            }
        }
        printf("%s %s\n",firstIn,lastOut);
    }
    
    return 0;
}

E - ZOJ问题

 

对给定的字符串(只包含'z','o','j'三种字符),判断他是否能AC。 

是否AC的规则如下: 
1. zoj能AC; 
2. 若字符串形式为xzojx,则也能AC,其中x可以是N个'o' 或者为空; 
3. 若azbjc 能AC,则azbojac也能AC,其中a,b,c为N个'o'或者为空;
Input
输入包含多组测试用例,每行有一个只包含'z','o','j'三种字符的字符串,字符串长度小于等于1000;
Output
对于给定的字符串,如果能AC则请输出字符串“Accepted”,否则请输出“Wrong Answer”。
Sample Input
zoj
ozojo
ozoojoo
oozoojoooo
zooj
ozojo
oooozojo
zojoooo
Sample Output
Accepted
Accepted
Accepted
Accepted
Accepted
Accepted
Wrong Answer
Wrong Answer

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 1010;
char in[maxn];
bool killme(int p,char x){
    if(in[p]!=x){
        printf("Wrong Answer\n");
        return true;
    }
    return false;
}
int main(){
    while(~scanf("%s",in)){
        getchar();
        if(!strcmp(in, "zj")){
            printf("Wrong Answer\n");
            continue;
        }
        int a = 0,b = 0, c = 0;
        int n = 0, p = 0,len = strlen(in);
        while(in[p]!='z'&&p<len&&in[p]=='o'){
            a++;
            p++;
        }
        if(killme(p,'z')) continue;
        p++;
        while(in[p]!='j'&&p<len&&in[p]=='o'){
            p++;
            b++;
        }
        if(killme(p,'j')) continue;
        p++;
        while(p<len&&in[p]=='o'){
            p++;
            c++;
        }
        if(p<len&&killme(p,'o')) continue;
        if(a*b==c){
            printf("Accepted\n");
        }else{
            printf("Wrong Answer\n");
        }
    }
    return 0;
}

F - A+B

 

给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号","隔开。 
现在请计算A+B的结果,并以正常形式输出。 
Input
输入包含多组数据数据,每组数据占一行,由两个整数A和B组成(-10^9 < A,B < 10^9)。
Output
请计算A+B的结果,并以正常形式输出,每组数据占一行。
Sample Input
-234,567,890 123,456,789
1,234 2,345,678
Sample Output
-111111101
2346912

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 15;
void change(char *s,int len,long long &a){
    int p = 0;
    for(int i=len-1;i>=0;i--){
        if(s[i]==','){
            continue;
        }
        if(i==0&&s[i]=='-'){
            a = -a;
            break;
        }
        a += (s[i]-'0')*pow(10, p++);
    }
}
int main(){
    char s1[maxn],s2[maxn];
    int i,j;
    while(~scanf("%s %s",s1,s2)){
        getchar();
        long long a = 0, b = 0;
        int lena = strlen(s1), lenb = strlen(s2);
        change(s1,lena,a);
        change(s2,lenb,b);
        printf("%lld\n",a+b);
        
    }
    return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值