题目说明
测试笔试有三道题目 A、B、C。C 题最简单,B 题次之,A 题有些困难,分值也是越简单的分值越少,but,比较简单的 B 题实际上却又最高分值 22 pt !(A 大小测试集分值分别是 21pt/12pt,C 大小测试集分值分别是 6pt/4pt。) 看来到时候题目未必要按照顺序做呀,最初大家都上来做 A 题,但又不能轻易搞定,时间耽误了,成绩却没有,O__O"…
题目说明都很长,但是实际上表达的意思或是抽象出来说明其实都很简单,下面就说题目到底是要干嘛:
- A : 有一些人,他们一些是冤家,现在给很多这样的“冤家对”,问给的这些人是否可以分成两组,每一组里面没有冤家,给出 Yes 或是 No !
- B : 将一个小球在地面上和水平面成 θ 角以速度 v 抛出,落地时抛出的水平距离是 D ,已知 v 和 D,求 θ。(重力加速度 g = 9.8 m/s2。) [喔屮,这完全就是一个高中物理题丫,有木有!]
- C : 有一系列数字,比如 2 3 4 1 5,从前向后扫描,比较当前的数字和前面的数字,如果发现不是递增顺序,比如扫描到 1 发现比 4 小,那么将 1 插到前面的正确位置处,记操作1 次,问一个序列要变成一个递增的顺序需要操作几次 ?(前面的例子需要操作 1 次;而 4 3 2 1 需要操作 3 次!)
题目分析
C 题其实最简单,这里不需要排序,me 们只需要记住前面的最大的数字 max,如果被扫描的数字 d 比它 max 大,那么更新 max 的值,而操作次数不用 +1;如果 d 比 max 小,那么操作次数 +1,然后直接扫描下一个。完全是顺序扫描一遍就可以 okay 的题目。
B 题是个物理题目,所以需要动手演算一下计算公式。小球在水平方向上作匀速直线运动,在竖直方向上作上抛或是说自由落体运动,所以:
vcosθ⋅t = D 2vsinθ = g⋅t ∴ sin(2θ) = gD/v2
所以,这个题目实际上只要根据公式计算即可。(不过 c/c++ 库的 asin 求出的结果是弧度,所以还需要转换为角度 :π = 180° )
A 题貌似才是不好解决的问题。me 最初想:要划分成两组,当然根据第一对冤家就可以分成两组,比如 a b,a 是一组,b 是在一组,后米遇到 a c 的情况那么 b c 就是同一组。不过想想如果遇到 d f 的情况呢?猜测 d 和 a 一组,后来可能发现不对;然后再猜测 d 和 b 一组?这样的话,再遇到 g 和 h 情形,然后再两次猜测 ? 最初认为划分成两组完全不需要用到“并查集”的结构,不过后来还是使用并查集解决了。me 以前碰到过一个“朋友的朋友还是朋友,敌人的敌人也是朋友”这个题目,后来基本就是在原来的程序上修改了一下 AC 掉这道题目了。
A 题答题思路:首先保存所有这样的冤家对,然后遍历所有这样的对,比如 a b;查找所有和 a 有冤家关系的,那么和 b 并在一起;再查找和 b 有冤家关系的,和 a 并在一起;处理的结果就是这些人尽可能滴合并在了一起(合并在一起的必须分配在同一组),最后重新扫描冤家关系,如果发现有两个竟然分到了同一组那么 No,如果没有那么就是 Yes !
如果按照上面的思路处理,实际上会得到很多组,然后对这些组其实可以合并成两组;不过因为题目不需要,所以 me 们也没有保存多余的信息然后最后合并。
A题:
#include <iostream>
#include <cstring>
#include <map>
using namespace std;
const int MAX = 105;
int parent[MAX];
int enemy[MAX][MAX];
int find_set(int node)
{
int p = parent[node];
while(p != 0){
node = p;
p = parent[p];
}
return node;
}
void union_set(int pa, int pb)
{
parent[pb] = pa;
}
void friends(int a, int b)
{
int pa = find_set(a);
int pb = find_set(b);
if(pa != pb)
union_set(pa, pb);
}
int main()
{
int i, j, k, n, r;
string a, b;
map<string, int> table;
bool ok;
int ra, rb;
int value = 0;
cin >> r;
r = 1;
while(cin >> n){
memset(parent, 0, sizeof(parent));
memset(enemy, 0, sizeof(enemy));
for(i=0; i<n; ++i){
cin >> a >> b;
if(table[a] == 0)
table[a] = ++value;
if(table[b] == 0)
table[b] = ++value;
enemy[table[a]][table[b]] = enemy[table[b]][table[a]] = 1;
}
n = table.size();
for(i=1; i<=n; ++i)
for(j=1; j<=n; ++j){
if(!enemy[i][j])
continue;
for(k=1; k<=n; ++k)
if(enemy[i][k] == 1 && k!=j) // line i
friends(j, k);
for(k=1; k<=n; ++k)
if(enemy[k][j] == 1 && k!=i) // column j
friends(i, k);
}
ok = true;
for(i=1; i<=n && ok; ++i)
for(j=1; j<=n && ok; ++j){
if(enemy[i][j] == 0)
continue;
ra = find_set(i);
rb = find_set(j);
if(ra == rb){
ok = false;
}
}
cout << "Case #" << r << ": " << (ok?"Yes":"No") << '\n';
++r;
}
return 0;
}
B题:
#include <stdio.h>
#include <math.h>
int main()
{
int n;
int v, d;
double svalue, th, g=9.8, pi=3.141592653;
scanf("%d", &n);
n = 1;
while(scanf("%d %d", &v, &d) != EOF){
svalue = d*g/(v*v);
th = asin(svalue)/pi*90;
printf("Case #%d: %.7f\n", n, th);
++n;
}
return 0;
}
C题:
#include <stdio.h>
#include <string.h>
#define N 105
#define MAX 105
int main()
{
int i, k, n, count;
char card[N][MAX], *max;
scanf("%d", &k);
k = 1;
while(scanf("%d", &n) != EOF){
count = 0;
getchar();
for(i=0; i<n; ++i)
fgets(card[i], MAX, stdin);
for(i=1, max=card[0]; i<n; ++i){
if(strcmp(max, card[i]) > 0){
++count;
}else{
max = card[i];
}
}
printf("Case #%d: %d\n", k, count);
++k;
}
return 0;
}