2014年Google中国校园招聘采用在线技术笔试,在Code Jam平台上,14号9点到15号9点开放测试题,帮助大家熟悉环境。这个周末也有够忙的,当时就上去看了一下,把输入文件下了一下,今天才把题目做了,对于我这个EE到CS的水军来说,通过做这个测试还是学到了很多东西的,值得总结一下。
其实三道题都不是很难,至少逻辑不算难,但是实现起来我就发现我真的是一只小小小菜鸟…要学的东西实在是太多太多~
先说第一题吧,在这三道题里面算相对难的了
Problem A. Bad Horse
As the leader of the Evil League of Evil, Bad Horse has a lot of problems to deal with. Most recently, there have been far too many arguments and far too much backstabbing in the League, so much so that Bad Horse has decided to split the league into two departments in order to separate troublesome members. Being the Thoroughbred of Sin, Bad Horse isn't about to spend his valuable time figuring out how to split the League members by himself. That what he's got you -- his loyal henchman -- for.
The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a positive integer M on a line by itself -- the number of troublesome pairs of League members. The next M lines each contain a pair of names, separated by a single space.
For each test case, output one line containing "Case #x: y", where x is the case number (starting from 1) and y is either "Yes" or "No", depending on whether the League members mentioned in the input can be split into two groups with neither of the groups containing a troublesome pair.
1 ≤ T ≤ 100.
Each member name will consist of only letters and the underscore character.
Names are case-sensitive.
No pair will appear more than once in the same test case.
Each pair will contain two distinct League members.
1 ≤ M ≤ 10.
1 ≤ M ≤ 100.
Input | Output |
2 1 Dead_Bowie Fake_Thomas_Jefferson 3 Dead_Bowie Fake_Thomas_Jefferson Fake_Thomas_Jefferson Fury_Leika Fury_Leika Dead_Bowie |
Case #1: Yes Case #2: No |
我会说,我着实不喜欢这些个英文描述吗。。理解问题就理解了半天…最终发现就是一个用染色就可以解决的问题。
思路倒是很容易有,但是实现起来…
读写文件就把我这个菜鸟卡了好一会儿,搜了一下发现其实还蛮简单的,比我想象的要简单很多,具体就看代码吧。
有了数据了,然后就是处理数据。因为是菜鸟,所以,所有的结构我都是用数组自己去实现的…先是把每个名字对应一个编号,每次一个新名字都要花O(n)的时间复杂度去查找是不是已经存在了,好在数据量很小,一个case里面最多也就20个名字,(或者200个,总之对计算机来说是很小的)。然后,建立一个二维数组,相当于把这些人之间的关系建立起来,这样,把数据遍历一遍就可以建起来这个结构。然后再用染色的方法去处理这个二维数组就好。
后来看到有人用map建立名字和编号的对应关系,这样查找复杂度就是O(log n)了,代码也简单了很多,之前没用过,这次学习了。
另外,我建立二维数组大小都是固定的,20*20,看到有人用vector,可以相当于动态数组,学习了。
所以,看到这些之后,为了能真正理解,我把之前的代码基于这两个结构重新实现了一遍。代码如下:
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 #include <vector> 5 #include <map> 6 using namespace std; 7 8 bool IsTwoLeague(vector<int> graph[20], int *league, int index) 9 { 10 for(int i = 0; i < graph[index].size(); ++i) 11 { 12 int nameNum = graph[index][i]; 13 if(league[nameNum] == -1) 14 { 15 league[nameNum] = 1 - league[index]; 16 if(!IsTwoLeague(graph, league, nameNum)) 17 return false; 18 } 19 else if(league[nameNum] == league[index]) 20 return false; 21 } 22 return true; 23 } 24 25 void AddNameToMap(map<string, int> &nameMap, string s) 26 { 27 if(!nameMap.count(s)) 28 nameMap.insert(pair<string, int>(s, nameMap.size())); 29 } 30 31 void BadHorse() 32 { 33 ifstream fin("A-small-1-attempt0.in"); 34 ofstream fout("A-small-1-attempt0.out"); 35 int numOfCases = 0; 36 fin >> numOfCases; 37 for(int i = 1; i <= numOfCases; ++i) 38 { 39 vector<int> graph[20]; 40 map<string, int> nameMap; 41 int caseNum = 0; 42 fin >> caseNum; 43 for(int i = 0; i < caseNum; ++i) 44 { 45 string name1, name2; 46 fin >> name1 >> name2; 47 AddNameToMap(nameMap, name1); 48 AddNameToMap(nameMap, name2); 49 graph[nameMap[name1]].push_back(nameMap[name2]); 50 graph[nameMap[name2]].push_back(nameMap[name1]); 51 } 52 int league[20]; 53 memset(league, -1, sizeof(league)); 54 int numOfNames = nameMap.size(); 55 bool rel = true; 56 for(int i = 0; i < numOfNames; ++i) 57 { 58 if(league[i] == -1) 59 { 60 league[i] = 0; 61 rel = IsTwoLeague(graph, league, i); 62 if(!rel) 63 break; 64 } 65 } 66 if(rel) 67 fout << "Case #" << i << ": " << "Yes" << endl; 68 else 69 fout << "Case #" << i << ": " << "No" << endl; 70 } 71 fin.close(); 72 fout.close(); 73 } 74 75 int main() 76 { 77 BadHorse(); 78 }
Problem B. Captain Hammer
The Hamjet is a true marvel of aircraft engineering. It is a jet airplane with a single engine so powerful that it burns all of its fuel instantly during takeoff. The Hamjet doesn't have any wings because who needs them when the fuselage is made of a special Wonderflonium isotope that makes it impervious to harm.
Piloting the Hamjet is a not a job for your typical, meek-bodied superhero. That's why the Hamjet belongs to Captain Hammer, who is himself impervious to harm. The G-forces that the pilot endures when taking a trip in the Hamjet are legen-dary.
The Hamjet takes off at an angle of θ degrees up and a speed of V meters per second. Vis a fixed value that is determined by the awesome power of the Hamjet engine and the capacity of its fuel tank. The destination is D meters away. Your job is to program the Hamjet's computer to calculate θ given V and D.
Fortunately, the Hamjet's Wondeflonium hull is impervious to air friction. Even more fortunately, the Hamjet doesn't fly too far or too high, so you can assume that the Earth is flat, and that the acceleration due to gravity is a constant 9.8 m/s2 down.
The first line of the input gives the number of test cases, T. T lines follow. Each line will contain two positive integers -- V and D.
For each test case, output one line containing "Case #x: θ", where x is the case number (starting from 1) and θ is in degrees up from the the horizontal. If there are several possible answers, output the smallest positive one.
An answer will be considered correct if it is within 10-6 of the exact answer, in absolute or relative error. See the FAQ for an explanation of what that means, and what formats of floating-point numbers we accept.
1 ≤ T ≤ 4500;
1 ≤ V ≤ 300;
1 ≤ D ≤ 10000;
It is guaranteed that each test case will be solvable.
Input | Output |
3 98 980 98 490 299 1234 |
Case #1: 45.0000000 Case #2: 15.0000000 Case #3: 3.8870928 |
这个题其实就是一道很简单的物理题…有了上一题的成长,这一题写起来着实没啥难度,大家都是理工科出身,公式我就不列了,你们懂的。
这道题里面学习到的一个小点就是,cout 在输出 float 或者 double 的时候,对于 45.0000000 这种数它只显示 45,如果要想固定精度,需要设置一下
fout << "Case #" << i << ": " << fixed << setprecision(7) << theta << endl;其中 setprecision 需要包含头文件 #include <iomanip>。
1 #include <iostream> 2 #include <fstream> 3 #include <iomanip> 4 using namespace std; 5 6 void CaptainHammer() 7 { 8 ifstream fin("B-small-attempt0.in"); 9 ofstream fout("B-small-attempt0.out"); 10 double g = 9.8; 11 double pi = acos(-1.0); 12 int numOfCases = 0; 13 fin >> numOfCases; 14 for(int i = 1; i <= numOfCases; ++i) 15 { 16 int v, d; 17 fin >> v >> d; 18 double theta = asin(g * d / (v * v)) / 2; 19 theta = theta * 180 / pi; 20 fout << "Case #" << i << ": " << fixed << setprecision(7) << theta << endl; 21 } 22 fin.close(); 23 fout.close(); 24 } 25 26 int main() 27 { 28 CaptainHammer(); 29 }
Problem C. Moist
Moist has a hobby -- collecting figure skating trading cards. His card collection has been growing, and it is now too large to keep in one disorganized pile. Moist needs to sort the cards in alphabetical order, so that he can find the cards that he wants on short notice whenever it is necessary.
The problem is -- Moist can't actually pick up the cards because they keep sliding out his hands, and the sweat causes permanent damage. Some of the cards are rather expensive, mind you. To facilitate the sorting, Moist has convinced Dr. Horrible to build him a sorting robot. However, in his rather horrible style, Dr. Horrible has decided to make the sorting robot charge Moist a fee of $1 whenever it has to move a trading card during the sorting process.
Moist has figured out that the robot's sorting mechanism is very primitive. It scans the deck of cards from top to bottom. Whenever it finds a card that is lexicographically smaller than the previous card, it moves that card to its correct place in the stack above. This operation costs $1, and the robot resumes scanning down towards the bottom of the deck, moving cards one by one until the entire deck is sorted in lexicographical order from top to bottom.
As wet luck would have it, Moist is almost broke, but keeping his trading cards in order is the only remaining joy in his miserable life. He needs to know how much it would cost him to use the robot to sort his deck of cards.
The first line of the input gives the number of test cases, T. T test cases follow. Each one starts with a line containing a single integer, N. The next N lines each contain the name of a figure skater, in order from the top of the deck to the bottom.
For each test case, output one line containing "Case #x: y", where x is the case number (starting from 1) and y is the number of dollars it would cost Moist to use the robot to sort his deck of trading cards.
1 ≤ T ≤ 100.
Each name will consist of only letters and the space character.
Each name will contain at most 100 characters.
No name with start or end with a space.
No name will appear more than once in the same test case.
Lexicographically, the space character comes first, then come the upper case letters, then the lower case letters.
1 ≤ N ≤ 10.
1 ≤ N ≤ 100.
Input | Output |
2 2 Oksana Baiul Michelle Kwan 3 Elvis Stojko Evgeni Plushenko Kristi Yamaguchi |
Case #1: 1 Case #2: 0 |
我会说这道题我其实没看太懂吗。。。我的理解就是,对于一个 case,从上往下扫描,遇到一个不合排序法则的,就把已经扫描的这部分排序,付$1。比如
c d b a
扫到 b,发现不对,应该变为 b c d,付$1,然后,再碰到 a,又不对,应该是 a b c d,付$1。这个 case 就是$2。
这样的话,只需要维护一个扫描过的这部分的最大字符串就好了,碰到比这个字符串大的就更新这个字符串,碰到比这个字符串小的说明顺序有问题,dollar++。对于上面的例子,max = c, dollar = 0; d > max, max = d; b < max, dollar++; a < d, dollar++。我觉得这样有点太简单,所以一直怀疑我理解错了……
按我的理解的话,代码如下:
1 #include <iostream> 2 #include <fstream> 3 #include <string> 4 using namespace std; 5 6 void Moist() 7 { 8 ifstream fin("C-small-1-attempt0.in"); 9 ofstream fout("C-small-1-attempt0.out"); 10 int numOfCases = 0; 11 fin >> numOfCases; 12 for(int i = 1; i <= numOfCases; ++i) 13 { 14 int caseNum = 0; 15 fin >> caseNum; 16 int dollars = 0; 17 string sMax; 18 string s; 19 getline(fin, s); 20 for(int i = 1; i <= caseNum; ++i) 21 { 22 getline(fin, s); 23 if(s < sMax) 24 ++dollars; 25 else if(s > sMax) 26 sMax = s; 27 } 28 fout << "Case #" << i << ": " << dollars << endl; 29 } 30 fin.close(); 31 fout.close(); 32 } 33 34 int main() 35 { 36 Moist(); 37 }
总之,还是学到了很多东西的,我这只小小小菜鸟要继续努力。