2019北京大学研究生推免上机考试

百炼oj

A:有趣的跳跃
总时间限制: 1000ms 内存限制: 65536kB
描述
一个长度为n(n>0)的序列中存在“有趣的跳跃”当前仅当相邻元素的差的绝对值经过排序后正好是从1到(n-1)。例如,1 4 2 3存在“有趣的跳跃”,因为差的绝对值分别为3,2,1。当然,任何只包含单个元素的序列一定存在“有趣的跳跃”。你需要写一个程序判定给定序列是否存在“有趣的跳跃”。

输入
一行,第一个数是n(0 < n < 3000),为序列长度,接下来有n个整数,依次为序列中各元素,各元素的绝对值均不超过1,000,000,000。
输出
一行,若该序列存在“有趣的跳跃”,输出"Jolly",否则输出"Not jolly"。
样例输入
4 1 4 2 3
样例输出
Jolly

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
const int INF=3000;

int n=0;
int in[INF];
int cha[INF];

int main(){
    memset(cha,0,sizeof(cha));
    scanf("%d",&n);
    scanf("%d",&in[0]);
    for(int i=1;i<n;i++){
        scanf("%d",&in[i]);
        cha[abs(in[i]-in[i-1])]=1;
    }
    for(int i=1;i<=n-1;i++){
        if(cha[i]==0){
            printf("Not Jolly");
            return 0;
        }
    }
    printf("Jolly");
    return 0;
}

B:玛雅历
总时间限制: 1000ms 内存限制: 65536kB
描述
上周末,M.A. Ya教授对古老的玛雅有了一个重大发现。从一个古老的节绳(玛雅人用于记事的工具)中,教授发现玛雅人使用了一个一年有365天的叫做Haab的历法。这个Haab历法拥有19个月,在开始的18个月,一个月有20天,月份的名字分别是pop, no, zip, zotz, tzec, xul, yoxkin, mol, chen, yax, zac, ceh, mac, kankin, muan, pax, koyab, cumhu。这些月份中的日期用0到19表示。Haab历的最后一个月叫做uayet,它只有5天,用0到4表示。玛雅人认为这个日期最少的月份是不吉利的,在这个月法庭不开庭,人们不从事交易,甚至没有人打扫屋中的地板。

因为宗教的原因,玛雅人还使用了另一个历法,在这个历法中年被称为Tzolkin(holly年),一年被分成13个不同的时期,每个时期有20天,每一天用一个数字和一个单词相组合的形式来表示。使用的数字是1~13,使用的单词共有20个,它们分别是:imix, ik, akbal, kan, chicchan, cimi, manik, lamat, muluk, ok, chuen, eb, ben, ix, mem, cib, caban, eznab, canac, ahau。注意:年中的每一天都有着明确唯一的描述,比如,在一年的开始,日期如下描述: 1 imix, 2 ik, 3 akbal, 4 kan, 5 chicchan, 6 cimi, 7 manik, 8 lamat, 9 muluk, 10 ok, 11 chuen, 12 eb, 13 ben, 1 ix, 2 mem, 3 cib, 4 caban, 5 eznab, 6 canac, 7 ahau, ,8 imix, 9 ik, 10 akbal ……也就是说数字和单词各自独立循环使用。

Haab历和Tzolkin历中的年都用数字0,1,……表示,数字0表示世界的开始。所以第一天被表示成:
Haab: 0. pop 0
Tzolkin: 1 imix 0
请帮助M.A. Ya教授写一个程序可以把Haab历转化成Tzolkin历。

输入
Haab历中的数据由如下的方式表示:
日期. 月份 年数

输入中的第一行表示要转化的Haab历日期的数据量。下面的每一行表示一个日期,年数小于5000。
输出
Tzolkin历中的数据由如下的方式表示:
天数字 天名称 年数

第一行表示输出的日期数量。下面的每一行表示一个输入数据中对应的Tzolkin历中的日期。
样例输入
3
10. zac 0
0. pop 0
10. zac 1995
样例输出
3
3 chuen 0
1 imix 0
9 cimi 2801
来源
POJ 1008

#include <stdio.h>
#include <string>
#include <map>
using namespace std;

int n,td,tm,ty,totd,ad,am,ay,ads;
string tms;
map<string,int> hton;
map<int,string> ntot;

string ha[20]={"pop","no","zip",
                "zotz","tzec","xul",
                "yoxkin"," mol","chen",
                "yax","zac","ceh",
                "mac","kankin","muan",
                "pax","koyab","cumhu",
                "uayet"};

string ta[25]={"imix"," ik"," akbal",
                " kan"," chicchan"," cimi",
                " manik"," lamat"," muluk",
                " ok"," chuen"," eb",
                " ben"," ix"," mem",
                " cib"," caban"," eznab",
                " canac"," ahau"};

int main(){
    for(int i=0;i<19;i++){
        hton[ha[i]]=i;
    }
    for(int i=0;i<20;i++){
        ntot[i]=ta[i];
    }
    tms.resize(3);
    scanf("%d",&n);
    printf("%d\n",n);
    for(int i=0;i<n;i++){
        scanf("%d. %s %d",&td,&tms[0],&ty);
        tm=hton[tms];
        totd=ty*365+tm*20+td;
        ay=totd/(20*13);
        ads=totd%(20*13);
        am=ads%20;
        ad=ads%13;
        printf("%d %s %d\n",ad+1,ntot[am].c_str(),ay);
    }

    return 0;
}

C:走迷宫
总时间限制: 1000ms 内存限制: 65536kB
描述
一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。
给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。只能在水平方向或垂直方向走,不能斜着走。
输入
第一行是两个整数,R和C,代表迷宫的长和宽。( 1<= R,C <= 40)
接下来是R行,每行C个字符,代表整个迷宫。
空地格子用’.‘表示,有障碍物的格子用’#‘表示。
迷宫左上角和右下角都是’.’。
输出
输出从左上角走到右下角至少要经过多少步(即至少要经过多少个空地格子)。计算步数要包括起点和终点。
样例输入
5 5
…###
#…
#.#.#
#.#.#
#.#…
样例输出
9

#include <stdio.h>
#include <string>
#include <queue>
using namespace std;
const int INF=100;

struct Node{
    int nr,nc;
    int sp;
};

queue<Node> ge;
int mapp[INF][INF];
int r,c;
int dir[4][2]={1,0,
                0,1,
                -1,0,
                0,-1};


int main(){
    scanf("%d %d",&r,&c);
    char tp;
    for(int i=0;i<r;i++){
        for(int j=0;j<c;j++){
            scanf("%c",&tp);
            mapp[i][j]= tp=='.'?1:0;//1空地0物品
        }
    }
    Node temp,tnext;
    temp.nc=temp.nr=temp.sp=0;
    ge.push(temp);
    while(!ge.empty()){
        temp=ge.front();ge.pop();
        for(int i=0;i<4;i++){
            tnext=temp;
            tnext.nr+=dir[i][0];
            tnext.nc+=dir[i][1];
            tnext.sp++;
            printf("%d %d %d--\n",tnext.nr,tnext.nc,tnext.sp);
            if(tnext.nr>=r||tnext.nc>=c||tnext.nr<0||tnext.nc<0)
                continue;
            if(tnext.nr==r-1&&tnext.nc==c-1){
                printf("%d",tnext.sp+1);
                return 0;
            }
            ge.push(tnext);
        }
    }
    printf("No path\n");
    return 0;
}

D:最大上升子序列和
总时间限制: 1000ms 内存限制: 65536kB
描述
一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …,aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中序列和最大为18,为子序列(1, 3, 5, 9)的和.

你的任务,就是对于给定的序列,求出最大上升子序列和。注意,最长的上升子序列的和不一定是最大的,比如序列(100, 1, 2, 3)的最大上升子序列和为100,而最长上升子序列为(1, 2, 3)

输入
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000(可能重复)。
输出
最大上升子序列和
样例输入
7
1 7 3 5 9 4 8
样例输出
18

#include <stdio.h>
using namespace std;
const int INF=100;

int n,maxx=0;
int a[INF];
int dp[INF];

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    dp[0]=a[0];
    for(int i=1;i<n;i++){
        dp[i]=a[i];
        for(int j=0;j<i;j++){
            if(a[j]<=a[i]){
                dp[i]=(a[i]+dp[j])>dp[i]?(a[i]+dp[j]):dp[i];
            }
        }
        maxx=maxx>dp[i]?maxx:dp[i];
    }
    printf("%d",maxx);
    return 0;
}

E:酸奶厂
总时间限制: 1000毫秒 内存限制: 65536kB
描述
奶牛购买了一家酸奶厂,该酸奶厂生产举世闻名的Yucky酸奶。在接下来的N(1 <= N <= 10,000)周内,牛奶和劳动力的价格将每周波动,从而使公司在一周内生产一单位酸奶的成本为C_i(1 <= C_i <= 5,000)美分一世。经过精心设计的Yucky工厂,每周可生产任意数量的酸奶。

Yucky Yogurt拥有一个仓库,可以按每周每单位酸奶S(1 <= S <= 100)美分的固定费用存储未使用的酸奶。幸运的是,酸奶不会变质。Yucky酸奶的仓库很大,因此可以容纳许多单位的酸奶。

Yucky希望找到一种方法来每周向其客户交付Y_i(0 <= Y_i <= 10,000)单位酸奶(Y_i是第i周的交付量)。帮助Yucky在整个N周的时间内最大程度地降低其成本。第i周生产的酸奶以及已经储存的任何酸奶都可以用来满足Yucky当周的需求。
输入
*第1行:两个以空格分隔的整数N和S。

*第2…N + 1行:第i + 1行包含两个以空格分隔的整数:C_i和Y_i。
输出
*第1行:第1行包含一个整数:满足酸奶时间表的最低总成本。请注意,对于32位整数,总数可能太大。
样例输入
4 5
88 200
89 400
97 300
91 500
样例输出
126900

#include <stdio.h>
using namespace std;
const int INF=10020;

int n,s;
int a[INF][2];
long long int tot=0;

int main(){
    scanf("%d %d",&n,&s);
    for(int i=0;i<n;i++){
        scanf("%d %d",&a[i][0],&a[i][1]);
        a[i][2]=0;
    }
    for(int i=0;i<n;i++){
        tot+=a[i][0]*a[i][1];
        if(i!=n-1){
            a[i+1][0]=a[i+1][0]<(a[i][0]+s)?a[i+1][0]:(a[i][0]+s);
        }
    }
    printf("%lld",tot);
    return 0;
}

无线网络
描述

东南亚发生地震。亚洲合作医疗队(ACM)已与膝上计算机建立了无线网络,但由于意外的余震袭击,网络中的所有计算机都被破坏了。电脑被一一修复,网络逐渐恢复工作。由于硬件限制,每台计算机只能直接与不超过d米的计算机通信。但是,每台计算机都可以视为其他两台计算机之间通信的中介,也就是说,如果计算机A和计算机B可以直接通信,或者有计算机C可以同时与A和B通信,则计算机A和计算机B可以通信。 B.

在修复网络的过程中,工作人员可以随时执行两种操作,即修复一台计算机或测试两台计算机是否可以通信。您的工作是回答所有测试操作。
输入项

第一行包含两个整数N和d(1 <= N <= 1001,0 <= d <= 20000)。N是计算机的数量,从1到N,而D是两台计算机可以直接通信的最大距离。在接下来的N行中,每行包含两个整数xi,yi(0 <= xi,yi <= 10000),这是N个计算机的坐标。从第(N + 1)行到输入的末尾,有一些操作,这些操作是一个接一个地执行的。每行包含以下两种格式之一的操作:
1.“ O p”(1 <= p <= N),表示修复计算机p。
2.“ S p q”(1 <= p,q <= N),表示测试计算机p和q是否可以通信。

输入不会超过300000行。
输出量

对于每项测试操作,如果两台计算机可以通信,则打印“ SUCCESS”,否则,请打印“ FAIL”。
题目描述

#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
const int INF=1010;
const double epss=1e-3;

int n,s,tpp,tp1,tp2;
char tp;
int point[INF][2];
int vis[INF];
int in[INF];

int dist(int a,int b){
    double r=pow((point[a][0]-point[b][0]),2);
    double t=pow((point[a][1]-point[b][1]),2);
    return sqrt(r+t);
}

int finrot(int a){
    if(in[a]!=-1){
         in[a]=finrot(in[a]);
         return in[a];
    }
    return a;
}

int join(int a,int b){
    in[finrot(a)]=finrot(b);
    return 0;
}

int main(){
    memset(vis,0,sizeof(vis));
    memset(in,-1,sizeof(in));
    scanf("%d %d",&n,&s);
    for(int i=1;i<=n;i++){
        scanf("%d %d",&point[i][0],&point[i][1]);
    }
    while(scanf("%c",&tp)!=EOF){//POJ要用cin scanf错了。
        if(tp=='O'){
            scanf("%d",&tpp);
            vis[tpp]=1;
            for(int i=1;i<=n;i++){
                if(i==tpp||vis[i]==0){
                    continue;
                }
                if(dist(tpp,i)<=s+epss){
                    join(tpp,i);
                }
            }
        }else if(tp=='S'){
            scanf("%d %d",&tp1,&tp2);
            tp1=finrot(tp1);
            tp2=finrot(tp2);
            if(tp1==tp2){
                printf("SUCCESS\n");
            }else{
                printf("FAIL\n");
            }
        }
    }
    return 0;
}

Kruskal算法,由短到长排序,生成最小生成树,倒数的s-1条边用卫星通讯代替,由前向后第p-1-(s-1)条边的长度就是所求
题解

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int INF=505;

struct Edge{
    int p1,p2;
    double dis;
};

struct Poin{
    int x,y;
};
Edge edge[INF*INF];
Poin poin[INF];
int in[INF];

double dist(int a,int b){
    double t1=pow((poin[a].x-poin[b].x),2);
    double t2=pow((poin[a].y-poin[b].y),2);
    return sqrt(t1+t2);
}

int cmp(Edge a,Edge b){
    return a.dis<b.dis;
}

int finrot(int i){
    if(in[i]!=-1){
        in[i]=finrot(in[i]);
        return in[i];
    }
    return i;
}

int join(int a,int b){
    a=finrot(a);
    b=finrot(b);
    if(a<b){
        in[b]=a;
    }
    else{
        in[a]=b;
    }
    return 0;
}

int main(){
    int n,satt,pott;
    scanf("%d",&n);
    while(n--){
        memset(in,-1,sizeof(in));
        int nedge=0;
        scanf("%d %d",&satt,&pott);
        for(int i=0;i<pott;i++){
            scanf("%d %d",&poin[i].x,&poin[i].y);
        }
        for(int i=0;i<pott;i++){
            for(int j=i+1;j<pott;j++){
                edge[nedge].p1=i;
                edge[nedge].p2=j;
                edge[nedge++].dis=dist(i,j);
            }
        }
        sort(edge,edge+nedge,cmp);
        for(int i=0,k=0;i<nedge;i++){
            int rp1=finrot(edge[i].p1);
            int rp2=finrot(edge[i].p2);
            if(rp1!=rp2){
                join(rp1,rp2);
                k++;
                if(k==pott-satt){
                    printf("%.2f\n",edge[i].dis);
                    break;
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值