车牌摇号 程序设计题
2016-09-02 18:40
141 查看
阿里面试题(车牌摇号问题)
题目大意:由于北京车牌紧张,如果需要车牌,需要在每月中旬进行摇号来获得车牌,获得车牌的概率由下面式子决定 money/100000. (money就是摇号时支付的预约金),如果摇中,与预约金用来买车牌,如果没有摇中,这预约金退回。如果你希望在6个月中摇到车牌,问在规定的时间摇到车牌,最少的期望金额是多少?
对于这个问题,可以直接用数学公式进行求解,可以列出如下计算公式:
(x1 * x1/100000)+ ( 1 - x1/100000) * (x2 * x2 /100000) + (1 - x1/100000) * (1 - x2/100000) * (x3 * x3 / 100000) + (1 - x1/100000) * (1 - x2/100000) *
(1 - x3/100000)*(x4* x4 / 100000) + (1 - x1/100000) * (1 - x2/100000) * (1 - x3/100000)*(1 - x4/100000)*(x5* x5 / 100000) +
(1 - x1/100000) * (1 - x2/100000) * (1 - x3/100000)*(1 - x4/100000)*(1 - x5/100000)*(100000)
对于求解上式,可以通过SGD (随机梯度下降法进行求解),代码如下:
除了这种通过数学求解,我们也可以通过动态规划的方式进行求解。如果我们考虑所有情况,时间复杂度太大,不过我们可以缩减动态规划的空间,让结果在可控范围内就行,代码如下:
结论:如果必须在6个月之内拿到拍照,期望金额是 100000 * 40%。可以思考,最后的期望金额只跟时间有关,跟100000没什么关系。
题目大意:由于北京车牌紧张,如果需要车牌,需要在每月中旬进行摇号来获得车牌,获得车牌的概率由下面式子决定 money/100000. (money就是摇号时支付的预约金),如果摇中,与预约金用来买车牌,如果没有摇中,这预约金退回。如果你希望在6个月中摇到车牌,问在规定的时间摇到车牌,最少的期望金额是多少?
对于这个问题,可以直接用数学公式进行求解,可以列出如下计算公式:
(x1 * x1/100000)+ ( 1 - x1/100000) * (x2 * x2 /100000) + (1 - x1/100000) * (1 - x2/100000) * (x3 * x3 / 100000) + (1 - x1/100000) * (1 - x2/100000) *
(1 - x3/100000)*(x4* x4 / 100000) + (1 - x1/100000) * (1 - x2/100000) * (1 - x3/100000)*(1 - x4/100000)*(x5* x5 / 100000) +
(1 - x1/100000) * (1 - x2/100000) * (1 - x3/100000)*(1 - x4/100000)*(1 - x5/100000)*(100000)
对于求解上式,可以通过SGD (随机梯度下降法进行求解),代码如下:
#include <iostream> #include <stdio.h> #include <vector> #include <map> #include <cmath> #include <time.h> #include <random> #include <set> #include <queue> #include <algorithm> using namespace std; #define inf 100000000 // ctrl + k and then press c 注释 // ctrl + k and then press u 取消注释 // ctrl + shift + L 删除当前行 // 用SGD求解 如下函数 // f(x0,x1,x2,x3,x4,x5) = x1 * x1 / money + (1 - x1/money) * x2 * x2 / money + (1 - x1/money) * (1 - x2/money) * x3 * x3 / money + ... + (1 - x1/money) * ...*(1 - x4/money) * x5 * x5 / money double lamba,money; double x[6]; // 控制变量值的范围 void Update(double& a,double gradient,double lamba) { //printf("a = %lf and gradient = %lf and lamba = %lf\n",a,gradient,lamba); double result = a - gradient * lamba; if(result >= 0 && result <= money) a = result; } // (1 - x1/money) * (1 - x2/money) * (1 - x3/money) * (1 - x4/money) * ...*(1 - xn/money) // excp 表示不乘以(1 - Xexcp/money) double cal_1_to_n(int n,int excp) { double tmp = 1.0; for(int i = 0;i<=n;i++) if(i != excp) { tmp *= (1 - x[i] / money); } return tmp; } int main() { double steps; printf("Please Input money = "); scanf("%lf",&money); //在题目中就100000 printf("Please Input steps = "); scanf("%lf",&steps); // 随机梯度迭代次数 printf("Please Input lamba = "); scanf("%lf",&lamba); //梯度下降时的步长 srand((unsigned)time(NULL)); // 随机种子 // 变量随机值 for(int i = 0 ;i< 6;i++) x[i] = rand() % (int(money) + 1); x[5] = money; double gradient; for(int i = 0;i<steps;i++) { for(int j = 0;j<5;j++) { // 计算梯度值 gradient = 2.0 * x[j] / money; gradient *= cal_1_to_n(j - 1,10); double tmp = 1.0; for(int k = j + 1;k<=5;k++) { tmp = cal_1_to_n(k-1,j); tmp *= x[k] * x[k] / money; tmp /= money; gradient -= tmp; } /*printf("steps = %d\n",i); printf("x[%d] gradient is %lf\n",j,gradient);*/ // 更新梯度值 Update(x[j],gradient,lamba); } double min_val = 0.0; // 计算期望值 for(int i = 0;i<6;i++) { min_val += cal_1_to_n(i-1,10) * x[i] * x[i] / money; } //每迭代100次 打印输出 if(i % 100 == 0) { for(int i = 0;i<6;i++) printf("x[%d] = %lf ",i,x[i]); printf("\n"); printf("the min_val is %lf\n",min_val); } } return 0; }
除了这种通过数学求解,我们也可以通过动态规划的方式进行求解。如果我们考虑所有情况,时间复杂度太大,不过我们可以缩减动态规划的空间,让结果在可控范围内就行,代码如下:
#include <iostream> #include <stdio.h> #include <vector> #include <map> #include <cmath> #include <set> #include <queue> #include <algorithm> using namespace std; #define inf 100000000 // ctrl + k and then press c 注释 // ctrl + k and then press u 取消注释 // ctrl + shift + L 删除当前行 int main() { int precision,money; printf("Please Input precision = "); scanf("%d",&precision); printf("Please Input money = "); scanf("%d",&money); double **dp = new double* [6]; for(int i = 0;i<6;i++) dp[i] = new double[precision + 1]; //dp[i][j] 表示第i轮过后,在没有拿到拍照的概率为j的情况下,花费最少的钱。 for(int i = 0;i<6;i++) for(int j = 0;j<=precision;j++) dp[i][j] = inf; dp[0][precision] = 0; for(int i = 0; i < 5;i++) { for(int j = 0;j<=precision;j++) { if(dp[i][j] < inf - 1) { for(int k = 0;k<=money;k++) { int no_card_rate = (int)(j - k * 1.0 * j/ money); // 对概率这一维进行压缩,只保留1/precision 的精度。 dp[i+1][no_card_rate] = min(dp[i+1][no_card_rate],dp[i][j] + (k * 1.0 * k * j /precision/ money)); } } } } double Min_val = inf; for(int i = 0;i<=precision;i++) { Min_val = min(Min_val,dp[5][i] + (i * 1.0/precision) * money); } cout << Min_val << endl; return 0; }
结论:如果必须在6个月之内拿到拍照,期望金额是 100000 * 40%。可以思考,最后的期望金额只跟时间有关,跟100000没什么关系。
相关文章推荐
- print_r输出数组,并制作车牌摇号
- 北京购车摇号满两年送车牌
- 车牌摇号、限行、交通拥堵未来会通通消失?阿里王坚说利用机器智能可以做到
- 北京车牌摇号-北京车牌摇号申请、流程、查询、及申请网站
- 杭州车牌摇号规则详细内容
- 摇号程序设计
- Linux设备驱动--块设备(三)之程序设计
- 程序设计原则
- 2014年第五届蓝桥杯C/C++程序设计本科B组决赛 年龄巧合(结果填空)
- 第八届福建大学生程序设计竞赛-B Triangles(简单计算几何)
- 算法竞赛入门经典 2.2 循环结构程序设计
- 系统性训练,励志刷完挑战程序设计竞赛-代码整理135~【中级篇】
- 2015年第六届蓝桥杯C/C++程序设计本科B组决赛 完美正方形(结果填空)
- fzu 2281 Trades [第八届福建省大学生程序设计竞赛 Problem J Trades] [贪心]
- MFC Window程序设计(第二版)精华浓缩笔记(二)
- C++程序设计实验报告(四十七)---第六周任务五
- 【1141】面向对象程序设计上机练习二(函数模板)
- 华中农业大学第四届程序设计大赛网络同步赛 G.Array C 线段树或者优先队列
- 51单片机 时钟程序设计 数码管可闪烁显示数值
- .NET平台下Web树形结构程序设计