|
|
package class13;
|
|
|
|
|
|
import java.text.DecimalFormat;
|
|
|
|
|
|
public class Code01_NCardsABWin {
|
|
|
|
|
|
// 谷歌面试题
|
|
|
// 面值为1~10的牌组成一组,
|
|
|
// 每次你从组里等概率的抽出1~10中的一张
|
|
|
// 下次抽会换一个新的组,有无限组
|
|
|
// 当累加和<17时,你将一直抽牌
|
|
|
// 当累加和>=17且<21时,你将获胜
|
|
|
// 当累加和>=21时,你将失败
|
|
|
// 返回获胜的概率
|
|
|
public static double f1() {
|
|
|
return p1(0);
|
|
|
}
|
|
|
|
|
|
// 游戏的规则,如上
|
|
|
// 当你来到cur这个累加和的时候,获胜概率是多少返回!
|
|
|
public static double p1(int cur) {
|
|
|
if (cur >= 17 && cur < 21) {
|
|
|
return 1.0;
|
|
|
}
|
|
|
if (cur >= 21) {
|
|
|
return 0.0;
|
|
|
}
|
|
|
double w = 0.0;
|
|
|
for (int i = 1; i <= 10; i++) {
|
|
|
w += p1(cur + i);
|
|
|
}
|
|
|
return w / 10;
|
|
|
}
|
|
|
|
|
|
// 谷歌面试题扩展版
|
|
|
// 面值为1~N的牌组成一组,
|
|
|
// 每次你从组里等概率的抽出1~N中的一张
|
|
|
// 下次抽会换一个新的组,有无限组
|
|
|
// 当累加和<a时,你将一直抽牌
|
|
|
// 当累加和>=a且<b时,你将获胜
|
|
|
// 当累加和>=b时,你将失败
|
|
|
// 返回获胜的概率,给定的参数为N,a,b
|
|
|
public static double f2(int N, int a, int b) {
|
|
|
if (N < 1 || a >= b || a < 0 || b < 0) {
|
|
|
return 0.0;
|
|
|
}
|
|
|
if (b - a >= N) {
|
|
|
return 1.0;
|
|
|
}
|
|
|
// 所有参数都合法,并且b-a < N
|
|
|
return p2(0, N, a, b);
|
|
|
}
|
|
|
|
|
|
// 游戏规则,如上,int N, int a, int b,固定参数!
|
|
|
// cur,目前到达了cur的累加和
|
|
|
// 返回赢的概率
|
|
|
public static double p2(int cur, int N, int a, int b) {
|
|
|
if (cur >= a && cur < b) {
|
|
|
return 1.0;
|
|
|
}
|
|
|
if (cur >= b) {
|
|
|
return 0.0;
|
|
|
}
|
|
|
double w = 0.0;
|
|
|
for (int i = 1; i <= N; i++) {
|
|
|
w += p2(cur + i, N, a, b);
|
|
|
}
|
|
|
return w / N;
|
|
|
}
|
|
|
|
|
|
// f2的改进版本,用到了观察位置优化枚举的技巧
|
|
|
// 可以课上讲一下
|
|
|
public static double f3(int N, int a, int b) {
|
|
|
if (N < 1 || a >= b || a < 0 || b < 0) {
|
|
|
return 0.0;
|
|
|
}
|
|
|
if (b - a >= N) {
|
|
|
return 1.0;
|
|
|
}
|
|
|
return p3(0, N, a, b);
|
|
|
}
|
|
|
|
|
|
public static double p3(int cur, int N, int a, int b) {
|
|
|
if (cur >= a && cur < b) {
|
|
|
return 1.0;
|
|
|
}
|
|
|
if (cur >= b) {
|
|
|
return 0.0;
|
|
|
}
|
|
|
if (cur == a - 1) {
|
|
|
return 1.0 * (b - a) / N;
|
|
|
}
|
|
|
double w = p3(cur + 1, N, a, b) + p3(cur + 1, N, a, b) * N;
|
|
|
if (cur + 1 + N < b) {
|
|
|
w -= p3(cur + 1 + N, N, a, b);
|
|
|
}
|
|
|
return w / N;
|
|
|
}
|
|
|
|
|
|
// f3的改进版本的动态规划
|
|
|
// 可以课上讲一下
|
|
|
public static double f4(int N, int a, int b) {
|
|
|
if (N < 1 || a >= b || a < 0 || b < 0) {
|
|
|
return 0.0;
|
|
|
}
|
|
|
if (b - a >= N) {
|
|
|
return 1.0;
|
|
|
}
|
|
|
double[] dp = new double[b];
|
|
|
for (int i = a; i < b; i++) {
|
|
|
dp[i] = 1.0;
|
|
|
}
|
|
|
if (a - 1 >= 0) {
|
|
|
dp[a - 1] = 1.0 * (b - a) / N;
|
|
|
}
|
|
|
for (int cur = a - 2; cur >= 0; cur--) {
|
|
|
double w = dp[cur + 1] + dp[cur + 1] * N;
|
|
|
if (cur + 1 + N < b) {
|
|
|
w -= dp[cur + 1 + N];
|
|
|
}
|
|
|
dp[cur] = w / N;
|
|
|
}
|
|
|
return dp[0];
|
|
|
}
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
int N = 10;
|
|
|
int a = 17;
|
|
|
int b = 21;
|
|
|
System.out.println("N = " + N + ", a = " + a + ", b = " + b);
|
|
|
System.out.println(f1());
|
|
|
System.out.println(f2(N, a, b));
|
|
|
System.out.println(f3(N, a, b));
|
|
|
System.out.println(f4(N, a, b));
|
|
|
|
|
|
int maxN = 15;
|
|
|
int maxM = 20;
|
|
|
int testTime = 100000;
|
|
|
System.out.println("测试开始");
|
|
|
System.out.println("比对double类型答案可能会有精度对不准的问题");
|
|
|
System.out.println("所以答案一律只保留小数点后四位进行比对");
|
|
|
System.out.println("如果没有错误提示, 说明验证通过");
|
|
|
DecimalFormat df = new DecimalFormat("#.####");
|
|
|
for (int i = 0; i < testTime; i++) {
|
|
|
N = (int) (Math.random() * maxN);
|
|
|
a = (int) (Math.random() * maxM);
|
|
|
b = (int) (Math.random() * maxM);
|
|
|
double ans2 = Double.valueOf(df.format(f2(N, a, b)));
|
|
|
double ans3 = Double.valueOf(df.format(f3(N, a, b)));
|
|
|
double ans4 = Double.valueOf(df.format(f4(N, a, b)));
|
|
|
if (ans2 != ans3 || ans2 != ans4) {
|
|
|
System.out.println("Oops!");
|
|
|
System.out.println(N + " , " + a + " , " + b);
|
|
|
System.out.println(ans2);
|
|
|
System.out.println(ans3);
|
|
|
System.out.println(ans4);
|
|
|
}
|
|
|
}
|
|
|
System.out.println("测试结束");
|
|
|
|
|
|
N = 10000;
|
|
|
a = 67834;
|
|
|
b = 72315;
|
|
|
System.out.println("N = " + N + ", a = " + a + ", b = " + b + "时, 除了方法4外都超时");
|
|
|
System.out.print("方法4答案: ");
|
|
|
System.out.println(f4(N, a, b));
|
|
|
}
|
|
|
|
|
|
}
|