2019北大計算機學科夏令營機試題目#
題目鏈接
密碼依然是fighting!
百練上北大夏令營的機試題目,但是很多都找不到可以提交網站的地方,只看了幾個能再Virtual Judge上的題目。感受就是題目很長,代碼量也不少,題目也有一定難度,時間也很短。總之就是“南”,這些人太厲害了吧!
大概有三個較為簡單的小模擬的題目。也沒有找到可以提交的OJ。
1.Hopscotch##
題目大意:跳房子的游戲,求一個數字變到另外一個數字最少操作步數。操作H和操作O分別定義如下:
-
if the stone falls into a house (marked as H), we can jump from the current house i to the house 3*i;
-
if the stone falls outside the house (marked as O), we can jump from the current house i to house i/2.(round down).
題目保證操作步數再25步之內。
題解:上面的條件很重要,使得這個題不考慮貪心和DP,而是BFS最短路的問題,因為深度最多25步,而且這個題需要保存路徑,輸出字典序最小的操作方案。
代碼是別人寫的,找不到提交的地方。
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <queue>
using namespace std;
int n, m;
struct node
{
int index;
int step;
vector<char> s; //記錄路徑
};
void BFS()
{
map<int, bool> mp;
queue<node> q;
node temp;
temp.index = n;
temp.step = 0;
q.push(temp);
while (!q.empty())
{
node top = q.front();
q.pop();
for (int i = 0; i < 2; i++)
{
node temp = top;
if (i == 0)
{
temp.index = top.index * 3;
temp.step = top.step + 1;
if (!mp[temp.index])
{
temp.s.push_back('H');
q.push(temp);
mp[temp.index] = true;
}
}
else
{
temp.index = top.index / 2;
temp.step = top.step + 1;
if (!mp[temp.index])
{
temp.s.push_back('O');
q.push(temp);
mp[temp.index] = true;
}
}
if (temp.index == m)
{
int len = temp.s.size();
cout << len << endl;
for (int i = 0; i < len; i++)
{
cout << temp.s[i];
}
cout << endl;
return;
}
}
}
}
int main()
{
while (cin >> n >> m)
{
if (n == 0 && m == 0)
{
break;
}
BFS();
}
return 0;
}
2. Falling Leaves##
題目大意:
一個二叉搜索樹,不斷刪除樹的葉子,給出葉子信息,求這個二叉搜索樹的先序遍歷。
題解:
逆向讀取輸入信息,也就是從頂向下構建這個二叉搜索樹,建樹之后先序遍歷即可。建樹操作還可以更加熟練一下。
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
const int N=30;
struct node{
char c;
node *l,*r;
node(char c='a',node *l=NULL,node *r=NULL):c(c),l(l),r(r){}
};
node tree[30];
int id;
node *insertTree(node *rt,char val){
if(rt==NULL){
tree[id].c=val;
tree[id].l=NULL;
tree[id].r=NULL;
return &tree[id++];//這里的下標不重要,只需要保存全部結點
}
if(val<rt->c)rt->l=insertTree(rt->l,val);
else rt->r=insertTree(rt->r,val);
return rt;
}
void preOrder(node *rt){
if(rt){
putchar(rt->c);
preOrder(rt->l);
preOrder(rt->r);
}
}
int main()
{
vector<char>ve;
char ch;
while(cin>>ch&&ch!='$'){
ve.clear();
ve.push_back(ch);
while(cin>>ch){
if(ch=='*'||ch=='$')break;
ve.push_back(ch);
}
node *root=NULL;
id=0;
for(int i=ve.size()-1;i>=0;i--){
root=insertTree(root,ve[i]);
}
preOrder(root);
puts("");
}
return 0;
}
3.昂貴的聘禮##
題目大意:
交換物品,不同等級的人有不同的物品交換,交換中需要支付一定的錢。eg:物品A+100=物品B。
限制條件是,在全部交換過程中,最高等級的人和最低等級的人等級差不能超過M。
題解:
原本還以為是DP,結果是我傻了。最短路問題,加上枚舉最低等級為minLevel的交換者,那么合法的交換者就是等級為minLevel到minLevel+M之間的人。交換建圖,額外付出的錢為路徑cost,注意方向性。時空復雜度可過,使用Dijkstra的朴素寫法即可。
#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int m,n;
const int N=105;
const int INF=0x3f3f3f3f;
int price[N],level[N];
int edge[N][N];
int vis[N];
int d[N];
void init(){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
edge[i][j]=INF;
}
}
for(int i=0;i<n;i++){
cin>>price[i]>>level[i];
level[i]--;//0開始
int x;
cin>>x;
for(int j=0;j<x;j++){
int v,p;
cin>>v>>p;
v--;
edge[v][i]=p;//v到i的價格為p
}
}
}
int dijkstr(){
for(int i=0;i<n;i++)d[i]=price[i];//把起點當作超級源點
for(int i=0;i<n;i++){
int temp=INF;
int x;//最小點
for(int j=0;j<n;j++)
if(vis[j]&&d[j]<=temp)
temp=d[x=j];
vis[x]=0;//不再走
for(int j=0;j<n;j++)
if(d[x]+edge[x][j]<d[j]&&vis[j])
d[j]=d[x]+edge[x][j];
}
return d[0];//0
}
int main()
{
cin>>m>>n;
init();
int ans=INF;
for(int i=0;i<n;i++){
int minLevel=level[i];//最小
for(int j=0;j<n;j++){
if(level[j]-minLevel>m||minLevel>level[j])
vis[j]=0;//不可
else vis[j]=1;
}
int cur=dijkstr();
// cout<<cur<<endl;
ans=min(ans,cur);
}
cout<<ans<<endl;
return 0;
}
原本還有兩個題,一個題目太長了,看不下去了,一個大模擬的題,我就放棄了。。。
