参考博文: 【题目自解】北京大学2016计算机学科夏令营上机考试
题目名称 | 题目类型 | 测试情况 |
---|---|---|
A 分段函数 | 模拟题 | AC |
B 单词翻转 | 模拟题 | AC |
C 反反复复 | 模拟题 | RE |
D 文件结构“图” | 递归回溯 | |
F Dungeon Master | BFS | |
G 重建二叉树 | 树 | AC |
H 丛林中的路 | 最小生成树 | AC |
A 分段函数
思路:简单题。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
double solve(double x)
{
double y;
if(x>=0 && x<5)
y = -x+2.5;
else if(x>=5 && x<10)
y = 2-1.5*(x-3)*(x-3);
else if(x>=10 && x<20)
y = x/2.0-1.5;
return y;
}
int main()
{
int x, y;
double N;
cin >> N;
printf("%.3f\n", solve(N));
return 0;
}
B 单词翻转
思路:简单模拟。我使用栈来翻转单词。
代码:
#include <iostream>
#include <cstdio>
#include <sstream>
#include <stack>
using namespace std;
int main()
{
string s, x;
stack<char> stc;
getline(cin, s);
s += ' ';
for(int i=0; i<s.size(); i++)
{
if(s[i]!=' ')
{
stc.push(s[i]);
}
else
{
while(!stc.empty())
{
printf("%c", stc.top());
stc.pop();
}
if(i!=s.size()-1)
printf(" ");
}
}
printf("\n");
return 0;
}
C 反反复复
思路:数组模拟题 。
代码:
#include<cstdio>
#include<cstring>
int N[205][205];
int main()
{
int m, n;//列和行
char s[205];
scanf("%d", &m);
scanf("%s", s);
int len = strlen(s);
n = len / m;
int cnt = 1;
for (int i = 0; i < n; i++)//按行读入
{
if (cnt % 2)//奇数行正向读入
{
for (int j = 0; j < m; j++)N[i][j] = s[i*m + j];
cnt++;
}
else//偶数行反向读入
{
for (int j = m - 1; j >= 0; j--)N[i][m - 1 - j] = s[i*m + j];
cnt++;
}
}
for (int j = 0; j < m; j++)//按列输出
{
for (int i = 0; i < n; i++)printf("%c", N[i][j]);
}
return 0;
}
D 文件结构“图”
思路:
代码:
#define TAB "| "
#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
using namespace std;
int cases=1;
char str[35];
bool isFinish=false;
void deal(int tab_num)//tab_num用来标记递归的层数
{
string file_name[35];
int file_num=0;
scanf("%s",str);
//输出格式
if (tab_num==0 && str[0]!='#')
{
if (cases>1)//不同测试之间有空行
printf("\n");
printf("DATA SET %d:\n",cases);
printf("ROOT\n");
}
while (true)
{
if (str[0]=='*' || str[0]==']')
break;
else if (str[0]=='#')
{
isFinish=true;
return;
}
else if (str[0]=='f')
file_name[file_num++]=str;
else if (str[0]=='d')
{
for (int i=0;i<tab_num+1;i++)
printf("%s",TAB);
printf("%s\n",str);
deal(tab_num+1);
}
scanf("%s",str);
}
//按大小输出文件
sort(file_name,file_name+file_num);
for (int i=0;i<file_num;i++)
{
for (int j=0;j<tab_num;j++)
printf("%s",TAB);
printf("%s\n",file_name[i].c_str());
}
return;
}
int main()
{
//freopen("output.txt","w",stdout);
while (!isFinish)
{
deal(0);
cases++;
}
return 0;
}
F Dungeon Master
思路:这道题是裸的BFS题,只不过变成了三维的图,实际上就是把遍历的方向扩展一下,主要是输入处理,字符之间无空格,应该按行输入。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
char G[35][35][35];
int vis[35][35][35];
string s;
int L, R, C;
int dx[10] = {0, 0, 0, 0, 1, -1};
int dy[10] = {0, 0, 1, -1, 0, 0};
int dz[10] = {1, -1, 0, 0, 0, 0};
struct Node
{
int x, y, z;
int step;
Node(int x=-1, int y=-1, int z=-1, int step = -1):x(x), y(y), z(z), step(step){}
};
Node st, ed;
void bfs(Node st)
{
memset(vis, 0, sizeof(vis));
queue<Node> q;
q.push(st);
vis[st.x][st.y][st.z] = 1;
while(!q.empty())
{
Node u = q.front(); q.pop();
for(int i=0; i<6; i++)
{
int x = u.x+dx[i], y = u.y+dy[i], z = u.z+dz[i];
if(x<0 || x>=L || y<0 || y>=R || z<0 || z>=C) continue;//出界
if(!vis[x][y][z] && G[x][y][z]!='#')
{
if(x==ed.x && y==ed.y && z==ed.z)//到达目标
{
printf("Escaped in %d minute(s).\n", u.step+1);
return;
}
vis[x][y][z] = 1;
q.push(Node(x, y, z, u.step+1));
}
}
}
printf("Trapped!\n");
}
int main()
{
while(scanf("%d%d%d", &L, &R, &C)!=EOF)
{
if(L+R+C==0) break;
//输入
for(int i=0; i<L; i++)
{
getchar();
for(int j=0; j<R; j++)
{
getline(cin, s);
for(int k=0; k<C; k++)
{
G[i][j][k] = s[k];
if(G[i][j][k]=='S')//出发点
{
st = Node(i, j, k, 0);
}
else if(G[i][j][k]=='E')//目标点
{
ed = Node(i, j, k);
}
}
}
}
bfs(st);
}
return 0;
}
G 重建二叉树
思路:根据前序和中序,输出后序。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
string pre, in;
int pos;
void rec(int l, int r)
{
if(l>=r) return;
char root = pre[pos++];
int mid = l;
while(in[mid]!=root) mid++;
rec(l, mid);
rec(mid+1, r);
printf("%c", root);
}
int main()
{
while(cin >> pre >> in)
{
pos = 0;
rec(0, pre.size());
printf("\n");
}
return 0;
}
H 丛林中的路
思路:求最小生成树权值之和,可以使用Prim和Kruskal。
Kruskal法:
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
struct Edge
{
int from, to, v;
Edge(int from=-1, int to=-1, int v=-1):from(from), to(to), v(v){}
bool operator < (const Edge &A) const
{
if(v==A.v)
{
if(from==A.from)
return to<A.to;
else
return from<A.from;
}
else
return v<A.v;
}
};
int father[200], Rank[200];
void Init()
{
for(int i=0; i<200; i++)
{
father[i] = i;
Rank[i] = 1;
}
}
int findRoot(int x)
{
int r = x;
while(father[r]!=r) r = father[r];
int j = x, i;
while(father[j]!=r)
{
i = father[j];
father[j] = r;
j = i;
}
return r;
}
void join(int x, int y)
{
int fx = findRoot(x), fy = findRoot(y);
if(fx==fy) return;
if(Rank[fx]>Rank[fy]) father[fy] = fx;
else
{
father[fx] = fy;
if(Rank[fx]==Rank[fy]) Rank[fy]++;
}
}
bool same(int x, int y)
{
return findRoot(x)==findRoot(y);
}
int main()
{
int n, m, cost;
char a, b;
while(cin >> n && n)
{
vector<Edge> E;
for(int i=1; i<n; i++)
{
cin >> a >> m;
for(int j=1; j<=m; j++)
{
cin >> b >> cost;
E.push_back(Edge(a-'A', b-'A', cost));
}
}
sort(E.begin(), E.end());
int sum = 0;
Init();
for(int i=0; i<E.size(); i++)
{
int f = E[i].from, t = E[i].to, v = E[i].v;
if(!same(f, t))
{
join(f, t);
sum += v;
}
}
printf("%d\n", sum);
}
return 0;
}