[关闭]
@tankle 2015-09-13T13:37:22.000000Z 字数 10088 阅读 2607

2015年网易游戏在线笔试

面试


题目4 : 好师父推算

时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
师徒系统普遍存在于各类网络游戏中,对于游戏促进新手留存具有重要意义,现在采集到如下信息:

好友个数 聊天次数 是否是好师父
1 3 1
2 1 2

希望你用naïve bayes算法基于“好友个数”和“聊天次数”推算某玩家是好师父的概率,以方便产品优化匹配规则。

输入
输入数据由多行构成,每行中的数据用“\t”分隔。第1行是1~3个用“\t”分隔的数字,表示输出第几个问题的答案,第2行是属性名称,包括fchatnum,cchatnum和remark三个属性,分别代表好友个数、聊天次数和是否是好师父。从第3行开始为训练数据,含义与第2行的属性名称相对应。好友个数和聊天次数取值都是1~10的整数,是否是好师父取值是1~2的整数,其中2表示好师父。

输出
根据第1行输入数据指定的编号输出以下3个小题的答案,多个小题答案使用换行“\n”分割。
第1题:输出好师父的先验概率。
第2题:输出好师父群体中好友个数取值的概率分布,依次对应1~10的概率取值,零值也要输出,中间用逗号分隔。
第3题:输出给定fchatnum=9,cchatnum=9的玩家是好师父的概率。
输出结果统一四舍五入保留小数点后3位。
完整样例输入下载
总计1000条数据,请在这里下载。
样例输入

  1. 1 2 3
  2. fchatnum cchatnum remark
  3. 1 2 1
  4. 3 3 1
  5. 1 1 1
  6. 6 9 2
  7. 3 7 2
  8. 4 6 2
  9. 4 2 2
  10. 3 8 2
  11. 1 1 1
  12. 8 4 2
  13. ……
  14. 样例输出
  15. 0.320
  16. 0.034,0.091,0.075,0.144,0.100,0.106,0.119,0.134,0.100,0.097
  17. 0.691
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <vector>
  6. #include <climits>
  7. #include <cmath>
  8. #include <map>
  9. using namespace std;
  10. void count(vector<int>& fchat, vector<int>& remark, vector<float>& num,int target){
  11. for(int i=0; i<remark.size(); i++){
  12. if(remark[i] == target){
  13. num[fchat[i]]++;
  14. }
  15. }
  16. }
  17. void output(int n, float goodrate, vector<float>& num, float threeres){
  18. switch (n) {
  19. case 1:
  20. printf("%.3f\n", goodrate);
  21. break;
  22. case 2:
  23. for(int i=1; i<num.size(); i++){
  24. if(i == num.size()-1)
  25. printf("%.3f\n", num[i]);
  26. else
  27. printf("%.3f,", num[i]);
  28. }
  29. break;
  30. case 3:
  31. printf("%.3f\n", threeres);
  32. break;
  33. }
  34. }
  35. int main(){
  36. vector<int> fchat;
  37. vector<int> cchat;
  38. vector<int> remark;
  39. int a, b,c;
  40. int one, two, three;
  41. scanf("%d %d %d", &one, &two, &three);
  42. map<string, vector<int>> str2vec;
  43. string s1, s2, s3;
  44. cin>>s1>>s2>>s3;
  45. while(cin>>a>>b>>c){
  46. // if(a == -1)
  47. // break;
  48. str2vec[s1].push_back(a);
  49. str2vec[s2].push_back(b);
  50. str2vec[s3].push_back(c);
  51. }
  52. fchat = str2vec["fchatnum"];
  53. cchat = str2vec["cchatnum"];
  54. remark = str2vec["remark"];
  55. int good = 0;
  56. for(int i=0; i<remark.size(); i++)
  57. if(remark[i] == 2)
  58. good++;
  59. float goodrate = good * 1.0 / remark.size();
  60. vector<float> num(11, 0);
  61. count(fchat, remark, num, 2);
  62. //好师傅的前提下,好友个数的概率分布
  63. for(int i=1; i<num.size(); i++){
  64. num[i] = num[i] * 1.0 / good;
  65. }
  66. vector<float> cnum(11, 0);
  67. count(cchat, remark, cnum, 2);
  68. for(int i=1; i<cnum.size(); i++) {
  69. cnum[i] = cnum[i] * 1.0 / good;
  70. }
  71. vector<float> num1(11,0);
  72. count(fchat, remark, num1, 1);
  73. vector<float> cnum1(11, 0);
  74. count(cchat, remark, cnum1, 1);
  75. float goodres = goodrate * num[9] * cnum[9];
  76. int notgood = remark.size() - good;
  77. float notres = (1 - goodrate) * num1[9] * cnum1[9] / (notgood * notgood);
  78. //NB公式
  79. float threeres = goodres / (goodres + notres);
  80. output(one, goodrate, num, threeres);
  81. output(two, goodrate, num, threeres);
  82. output(three, goodrate, num, threeres);
  83. return 0;
  84. }

题目3 : 游戏玩家分类

时间限制:25000ms
单点时限:5000ms
内存限制:256MB
描述
理查德•巴图博士通过对游戏中玩家固定的行为模式进行观察,于1996年提出了巴图模型,尝试把玩家的不同行为模式进行分类。他将游戏玩家分成了成就型、探索型、社交型和杀手型。该分类方式本质上从玩家在游戏中的需求出发,根据具体的行为表现对其进行分类。推断玩家所属类型,对于游戏用户研究,精准营销投放都有非常重要的意义,因此对不同玩家进行分类是一项重要研究工作。为了实现分类模型,通过收集玩家在游戏中的不同行为数据并进行归一化,可以得到玩家的特征向量以及已知类型玩家的标签,如:

副本参与次数 竞技场参与次数 任务完成次数 登陆频率 充值额度 玩家类型
0.8 0.5 0.6 0.9 0.2 A
0.4 0.8 0.1 0.2 0.1 B
0.9 0.1 0.5 0.6 0.9 C
0.5 0.2 0.1 0.3 0.0 D

(其中前五列数字为玩家的特征向量,最后一列字母是玩家类型,有A、B、C、D四种取值)

分类问题有多种解决算法,其中K最近邻(k-Nearest Neighbor,KNN)分类算法是最简单的机器学习算法之一,其思想是:如果一个样本在特征空间中的k个最相似的样本中的大多数属于某一个类别,则该样本也属于这个类别。请用该方法实现游戏玩家分类,距离度量函数采用欧氏距离。

输入
每个输入数据包含一组训练数据和一组测试数据。

第一行第一个数为KNN算法的k(k<=10000)值,第二个数为特征向量的长度L(L<=100),第三个数M(M>k, M<=10000)为训练数据行数,第四个数N(N<=10000)为测试数据行数。之后是M行训练数据和N行测试数据。每行中数据使用空格分隔。

输出
对于每行测试数据,输出该玩家的类型,例如“A”。如果前K个相似类型中,出现数量最多的类型有重复,则一起输出,以ABCD升序排列,例如“AC”。

样例输入

  1. 3 5 16 2
  2. 0.19 0.04 0.06 0.22 0.11 A
  3. 0.28 0.42 0.38 0.39 0.44 B
  4. 0.71 0.61 0.54 0.52 0.54 C
  5. 0.98 0.82 0.92 0.98 0.97 D
  6. 0.05 0.03 0.15 0.01 0.11 A
  7. 0.33 0.29 0.33 0.47 0.27 B
  8. 0.72 0.52 0.61 0.71 0.68 C
  9. 0.78 0.86 0.91 1.0 0.76 D
  10. 0.01 0.17 0.14 0.15 0.2 A
  11. 0.44 0.36 0.32 0.32 0.35 B
  12. 0.67 0.65 0.57 0.58 0.52 C
  13. 0.87 0.92 0.8 0.83 0.77 D
  14. 0.01 0.11 0.14 0.12 0.07 A
  15. 0.33 0.43 0.43 0.45 0.38 B
  16. 0.57 0.54 0.75 0.7 0.64 C
  17. 0.9 0.94 0.83 0.96 0.77 D
  18. 0.29 0.29 0.42 0.36 0.27
  19. 0.56 0.67 0.71 0.66 0.7
  20. 样例输出
  21. B
  22. C
  1. #include <iostream>
  2. #include <vector>
  3. #include <math.h>
  4. #include <map>
  5. #include <algorithm>
  6. using namespace std;
  7. struct sample {
  8. char label;
  9. double distance;
  10. };
  11. bool cmp1(sample a, sample b)
  12. {
  13. if (a.distance == b.distance)
  14. return a.label < b.label;
  15. return a.distance < b.distance;
  16. }
  17. bool cmp2(pair<char, int> a, pair<char, int> b)
  18. {
  19. if (a.second == b.second)
  20. return a.first < b.first;
  21. return a.second > b.second;
  22. }
  23. void readTrainData(vector<vector<double> > &trainData, vector<char> &trainLabel, int L, int M)
  24. {
  25. for (int i = 0; i < M; ++i) {
  26. // 读入训练数据特征
  27. vector<double> lineData;
  28. double tmpData;
  29. for (int j = 0; j < L; ++j) {
  30. cin >> tmpData;
  31. lineData.push_back(tmpData);
  32. }
  33. trainData.push_back(lineData);
  34. // 读入训练数据类别
  35. char label;
  36. cin >> label;
  37. trainLabel.push_back(label);
  38. }
  39. }
  40. void readTestData(vector<vector<double> > &testData, int L, int N)
  41. {
  42. for (int i = 0; i < N; ++i) {
  43. vector<double> lineData;
  44. double tmpData;
  45. for (int j = 0; j < L; ++j) {
  46. cin >> tmpData;
  47. lineData.push_back(tmpData);
  48. }
  49. testData.push_back(lineData);
  50. }
  51. }
  52. double calcDistance(vector<double> data1, vector<double> data2)
  53. {
  54. int length = data1.size();
  55. double distance = 0.0;
  56. for (int i = 0; i < length; ++i)
  57. distance += pow(data1[i] - data2[i], 2);
  58. return sqrt(distance);
  59. }
  60. void KNN(vector<vector<double> > trainData, vector<vector<double> > testData,
  61. vector<char> trainLabel, vector<char> &testLabel, int k, int L, int M, int N)
  62. {
  63. for (int i = 0; i < N; ++i) {
  64. // 计算每一个测试样本与所有训练样本的距离,并排序。
  65. vector<sample> distances;
  66. for (int j = 0; j < M; ++j) {
  67. sample tmpDistance;
  68. tmpDistance.distance = calcDistance(testData[i], trainData[j]);
  69. tmpDistance.label = trainLabel[j];
  70. distances.push_back(tmpDistance);
  71. }
  72. sort(distances.begin(), distances.end(), cmp1);
  73. //for (int j = 0; j < M; ++j)
  74. // cout << distances[j].distance << " " << distances[j].label << endl;
  75. //cout << "-------" << endl;
  76. // 选择前k个样本的距离,投票选择类别。
  77. map<char, int> labelMap;
  78. for (int j = 0; j < k; ++j) {
  79. if (!labelMap[distances[j].label])
  80. labelMap[distances[j].label] = 0;
  81. labelMap[distances[j].label] += 1;
  82. }
  83. //for (map<char, int>::iterator it = labelMap.begin(); it != labelMap.end(); ++it)
  84. // cout << (*it).first << " " << (*it).second << endl;
  85. //cout << "--------" << endl;
  86. for (int j = k; j < M; ++j) {
  87. if (distances[j].distance == distances[k-1].distance) {
  88. if (!labelMap[distances[j].label])
  89. labelMap[distances[j].label] = 0;
  90. labelMap[distances[j].label] += 1;
  91. }
  92. }
  93. //for (map<char, int>::iterator it = labelMap.begin(); it != labelMap.end(); ++it)
  94. // cout << (*it).first << " " << (*it).second << endl;
  95. //cout << "--------" << endl;
  96. vector<pair<char, int> > labelVec;
  97. for (map<char, int>::iterator it = labelMap.begin(); it != labelMap.end(); ++it)
  98. labelVec.push_back(make_pair((*it).first, (*it).second));
  99. sort(labelVec.begin(), labelVec.end(), cmp2);
  100. //for (int j = 0; j < labelVec.size(); ++j)
  101. // cout << labelVec[j].first << " " << labelVec[j].second << endl;
  102. //cout << "--------" << endl;
  103. string res = "";
  104. for (int j = 0; j < labelVec.size(); ++j) {
  105. res += labelVec[j].first;
  106. if (j + 1 >= labelVec.size() || labelVec[j].second != labelVec[j+1].second)
  107. break;
  108. }
  109. if (i == 0)
  110. cout << res;
  111. else
  112. cout << "\n" << res;
  113. }
  114. }
  115. int main()
  116. {
  117. int k, L, M, N;
  118. cin >> k >> L >> M >> N;
  119. vector<vector<double> > trainData;
  120. vector<vector<double> > testData;
  121. vector<char> trainLabel;
  122. vector<char> testLabel;
  123. readTrainData(trainData, trainLabel, L, M);
  124. readTestData(testData, L, N);
  125. KNN(trainData, testData, trainLabel, testLabel, k, L, M, N);
  126. return 0;
  127. }

题目2 : 理解SQL

时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
作为一名游戏行业的数据分析师,每天都会面对大量的游戏数据,对游戏数据进行统计分析必不可少。有效地使用SQL进行数据统计,可以帮助你在工作中获得事半功倍的效果。

请阅读以下SQL,理解SQL的语法含义,根据输入数据,编码输出该SQL的执行结果。

  1. SELECT
  2. ctype,
  3. COUNT(DISTINCT pid) AS pcnt,
  4. SUM(cash) AS cash
  5. FROM
  6. (
  7. SELECT
  8. player_channel.pid AS pid,
  9. player_channel.ctype AS ctype,
  10. prepaid.cash AS cash
  11. FROM
  12. (
  13. SELECT
  14. players.pid AS pid,
  15. IF(channels.ctype IS NULL, -1, channels.ctype) AS ctype
  16. FROM
  17. channels
  18. RIGHT OUTER JOIN
  19. players
  20. ON
  21. channels.cid=players.cid
  22. ) player_channel
  23. LEFT OUTER JOIN
  24. prepaid
  25. ON
  26. player_channel.pid=prepaid.pid
  27. ) channel_prepaid
  28. GROUP BY
  29. ctype
  30. ORDER BY
  31. cash DESC, ctype ASC
  32. ;

输入
包含SQL语句中涉及的表数据,每个表的相关数据由以下内容组成:

第一行包含两个数据:tname(字符串类型,长度不超过10,保证为有效单词)和m(0<=m<=1000),用空格分隔。其中tname表示该表的名字,m表示该表有m行数据;

第二行为3个字符串(保证为有效单词,长度不超过10),用空格分隔,表示该表的字段名,每个表的字段顺序如下,

channels 表包含字段:cid,name,ctype,其中cid为主键

players 表包含字段:pid,name,cid,其中pid为主键

prepaids 表包含字段:id,pid,cash,其中id为主键

接下来m行,每行3个用空格分隔的数据,仅name字段的数据为字符串类型(长度不超过10,保证为有效单词),其他均为非负整型。

输出
根据输入数据,输出SQL的执行结果。

  1. 样例输入
  2. channels 3
  3. cid name ctype
  4. 1 netease 0
  5. 2 iplay 0
  6. 3 appstore 1
  7. players 7
  8. pid name cid
  9. 1 Smith 1
  10. 2 Carter 2
  11. 3 Linda 2
  12. 4 Bush 3
  13. 5 Adam 4
  14. 6 Gates 5
  15. 7 Hill 1
  16. prepaids 8
  17. id pid cash
  18. 1 3 1000
  19. 2 4 3000
  20. 3 1 2000
  21. 4 6 1000
  22. 5 7 2000
  23. 6 2 2000
  24. 7 5 6000
  25. 8 3 2000
  26. 样例输出
  27. 0 4 9000
  28. -1 2 7000
  29. 1 1 3000

题解

  1. import re
  2. while True:
  3. try:
  4. data = {"channels": {"cid":[], "name":[], "ctype":[]},
  5. "players": {"pid":[], "name":[], "cid":[]},
  6. "prepaids": {"id":[], "pid":[], "cash":[]}}
  7. for i in range(3):
  8. name, num = input().split()
  9. num = int(num)
  10. a, b, c = input().split()
  11. for j in range(num):
  12. n1, n2, n3 = input().split()
  13. data[name][a].append(n1)
  14. data[name][b].append(n2)
  15. data[name][c].append(n3)
  16. player_channels = {"pid":[], "ctype":[], "cash":[]}
  17. channels = data["channels"]
  18. players = data["players"]
  19. prepaids = data["prepaids"]
  20. for i in range(len(players["pid"])):
  21. pid = players["pid"][i]
  22. player_channels["pid"].append(pid)
  23. cid = players["cid"][i]
  24. if cid not in channels["cid"]:
  25. type = "-1"
  26. else:
  27. type = channels["ctype"][channels["cid"].index(cid)]
  28. player_channels["ctype"].append(type)
  29. flag = 0
  30. for idx in range(len(prepaids["pid"])):
  31. pidd = prepaids["pid"][idx]
  32. if pidd == pid:
  33. if flag == 0:
  34. player_channels["cash"].append(prepaids["cash"][idx])
  35. flag = 1
  36. else:
  37. player_channels["pid"].append(pid)
  38. player_channels["ctype"].append(type)
  39. player_channels["cash"].append(prepaids["cash"][idx])
  40. # print(player_channels)
  41. results = {}
  42. ctypes = player_channels["ctype"]
  43. for i in range(len(ctypes)):
  44. ctype = ctypes[i]
  45. if ctype not in results:
  46. results[ctype] = {"pid":set(),"cash":0}
  47. results[ctype]["pid"].add(player_channels["pid"][i])
  48. results[ctype]["cash"] += int(player_channels["cash"][i])
  49. # print(results)
  50. res = []
  51. for key, value in results.items():
  52. res.append((int(key), len(value["pid"]), value["cash"]))
  53. from operator import itemgetter, attrgetter
  54. res = sorted(res,key=itemgetter(2, 0),reverse=True)
  55. for item in res:
  56. print(item[0],item[1],item[2])
  57. except EOFError:
  58. break

题目1 : 虚拟游戏世界实体分析

时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
虚拟游戏世界里面有很多实体,实体可能由很多子实体或者子属性构成。由于实体之间可能有非常之多的嵌套,查询某个实体或者属性属于第几层嵌套,以便将来对虚拟世界的修改和展示是一项待解决的问题,作为未来的虚拟世界分析员,你能用程序解决这个问题吗?

输入
输入数据可能由多组数据构成,每组数据由两行构成:

第一行是对虚拟世界的描述,实体或者属性由英文字母或者数字构成,子实体和子属性紧接着父实体嵌套在{}中,兄弟实体或者属性用“,”分隔。

第二行是要查询的属性或者实体,有且仅有一个。

注意数据输入可能很大。

输出
输出为查询的实体或者属性的层数;如果属性不存在,输出-1;如果有多个结果满足查询,请从小到大输出所有去重之后的结果,用”,”分隔

  1. 样例输入
  2. Fruit{apple{shape,color},orange{taste,price}}
  3. Fruit
  4. Fruit{apple{shape,color},orange{taste,price}}
  5. orange
  6. Fruit{apple{shape,color},orange{color,price},color}
  7. color
  8. 样例输出
  9. 1
  10. 2
  11. 2,3

题解

  1. import re
  2. while True:
  3. try:
  4. data = raw_input()
  5. sstr = raw_input()
  6. sstr = sstr.strip()
  7. res = re.findall(sstr, data)
  8. if len(res) == 0:
  9. print(-1)
  10. else:
  11. index = 1
  12. #将单词之间插入空格,方便后面的切分
  13. data = data.replace("{", " { ").replace("}", " } ").replace(",", " , ")
  14. data = data.split(" ")
  15. ress = set()
  16. level = 1
  17. for w in data:
  18. w = w.strip()
  19. if w == '{':
  20. level += 1
  21. elif w == '}':
  22. level -= 1
  23. elif w == sstr:
  24. ress.add(level)
  25. ress = list(ress)
  26. sorted(ress)
  27. out = ",".join([str(i) for i in ress ])
  28. print(out)
  29. except EOFError:
  30. break
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注