今天面试,遇到一个很有意思的题目,我们平常玩游戏,打怪时,怪物有一定几率掉落装备,怪物身上的装备有不同的比重,每次产生一个随机数,获得掉落的装备。
思路:
将装备的权值表达成区间长度,我们将所有节点的信息封装为三个id,L,R,这三个信息,相邻的两个节点的区间是相连的,所有节点的区间组成为一条未覆盖的线,这样我们就可以对区间点进行二分,或者现象查找,如果当前比重在节点区间中,就返回即可。
面试官说我思路太复杂了,(说实话感觉他没听懂我思路)。
实现代码+测试数据
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
class Node {
public:
Node() {}
Node(int id, int L, int R) : _id(id), _L(L), _R(R) {}
int _id, _L, _R;
Node(const Node& other) {
this->_id = other._id;
this->_L = other._L;
this->_R = other._R;
}
};
int main() {
srand(unsigned(time(NULL)));
vector<vector<int>> _vec{{1, 3}, {2, 5}, {3, 7}, {4, 8}, {5, 9},
{6, 20}, {7, 60}, {8, 90}, {9, 100}, {10, 35}};
vector<pair<int, double>> _rate;
double _sum = 0;
for (auto& s : _vec) {
_sum += s[1];
}
for (auto& s : _vec) {
_rate.push_back(make_pair(s[0], double(1.0 * s[1] / _sum)));
}
map<int, int> _nums;
int ktimes = 100000;
while (ktimes--) {
int _srands = rand();
vector<Node> NodeInfo;
NodeInfo.clear();
Node st;
for (int i = 0; i < 10; i++) {
if (i == 0) {
st._id = _vec[i][0];
st._L = 1;
st._R = _vec[i][1];
NodeInfo.push_back(st);
} else {
Node _st;
_st._id = _vec[i][0];
_st._L = st._R + 1;
_st._R = _st._L + _vec[i][1];
NodeInfo.push_back(_st);
st = _st;
}
}
_srands = (_srands % NodeInfo[NodeInfo.size() - 1]._R) + 1;
int _getId;
/*查找随机产生数所在区间的id*/
/*已验证在数据量很小的情况下,遍历的复杂度最优,本身身上的装备不超过4件*/
for (auto& x : NodeInfo) {
if (_srands >= x._L && _srands <= x._R) {
_getId = x._id;
break;
}
}
_nums[_getId]++;
}
int k = 0;
/*测试100000次,比较概率*/
for (auto& x : _nums) {
cout << "id: " << x.first << " startRate " << _rate[k++].second << ' '
<< "getRate " << double(x.second / 100000.0) << endl;
}
return 0;
}