《编程之美》284页,问题4.6:桶中取黑白球。

有一个桶,里面有白球、黑球各100个,人们必须按照以下规则把球取出来:

1. 每次从桶中拿两个球;

2. 如果两球同色,再放入一个黑球;

3. 如果两球异色,再放入一个白球;

问:最后桶里面只剩下一个黑球的概率是多少?

于是我开始分析,桶里装球,每次摸球是随机的,所以不能用队列和栈,那就用万能的动态列表来做桶吧。按照题目描述的顺序,写出取球的过程,最后剩的是黑球返回1,白球返回2,其他情况(没球了)返回3,然后根据概率在大数据量下将会趋于稳定的性质无限取球,最后趋于稳定的那个数就是答案。

代码如下(注释的部分为调试程序过程中用到的测试代码,用来显示操作过程中取球、放球、以及桶中球的详细变化过程):

using System;
using System.Collections.Generic;
using System.Linq; namespace BucketBall
{
class Program
{
static void Main(string[] args)
{
int count = ;
int targetCount = ;
int result;
double probability;
while (true)
{
List<string> bucketBalls = new List<string>();
result = Play(bucketBalls);
//Console.WriteLine("result:" + result);
if (result == )
{
targetCount++;
//Console.WriteLine("targetCount:" + targetCount);
}
count++;
//Console.WriteLine("count:" + count);
probability = Math.Round((double)1.0 * targetCount / count, );
Console.WriteLine(probability);
//Console.Read();
}
}
private static int Play(List<string> bucketBalls)
{
for (int i = ; i <= ; i++)
{
bucketBalls.Add("BlackBall");
bucketBalls.Add("WhiteBall");
}
//PrintList(bucketBalls);
Random ran = new Random();
while (bucketBalls.Count() > )
{ var balls = Take(bucketBalls, , ran);
//Console.WriteLine("Take the balls " + balls[0] + " " + balls[1]);
//PrintList(bucketBalls);
if (balls[] == balls[])
{
Put(bucketBalls, "BlackBall");
//Console.WriteLine("Put the BlackBall");
//PrintList(bucketBalls);
}
else
{
Put(bucketBalls, "WhiteBall");
//Console.WriteLine("Put WhiteBall over!");
//PrintList(bucketBalls);
}
//Console.WriteLine(bucketBalls.Count());
}
if (bucketBalls.Count() == )
{
//Console.WriteLine("result is " + bucketBalls[0]);
return bucketBalls[] == "BlackBall" ? : ;
}
else
{
return ;
}
} private static void PrintList(List<string> bucketBalls)
{
Console.WriteLine();
foreach (var ball in bucketBalls)
{
Console.Write(ball + " ");
}
Console.WriteLine();
} private static void Put(List<string> bucketBalls, string v)
{
bucketBalls.Add(v);
} private static List<string> Take(List<string> bucketBalls, int v, Random ran)
{
List<string> balls = new List<string>();
int pos;
for (int i = ; i <= v; i++)
{
pos = ran.Next(, bucketBalls.Count());
balls.Add(bucketBalls[pos]);
bucketBalls.RemoveAt(pos);
}
return balls;
}
}
}

我因为不小心将一处的“WhiteBall”写成了“WhileBall”而一度修改却得不到正确的答案,最终一步一步的通过上面的测试代码,才将出错范围最终锁定在了初始化bucketBalls的for循环内,最终发现我将“WhiteBall”写成了“WhileBall”。改过来以后,运行结果终于正确了。下面是去掉测试代码的最终版:

using System;
using System.Collections.Generic;
using System.Linq; namespace BucketBall
{
class Program
{
static void Main(string[] args)
{
int count = ;
int targetCount = ;
int result;
double probability;
while (true)
{
List<string> bucketBalls = new List<string>();
result = Play(bucketBalls);
if (result == )
{
targetCount++;
}
count++;
probability = Math.Round((double)1.0 * targetCount / count, );
Console.WriteLine(probability);
}
}
private static int Play(List<string> bucketBalls)
{
for (int i = ; i <= ; i++)
{
bucketBalls.Add("BlackBall");
bucketBalls.Add("WhiteBall");
}
Random ran = new Random();
while (bucketBalls.Count() > )
{ var balls = Take(bucketBalls, , ran);
if (balls[] == balls[])
{
Put(bucketBalls, "BlackBall");
}
else
{
Put(bucketBalls, "WhiteBall");
}
}
if (bucketBalls.Count() == )
{
return bucketBalls[] == "BlackBall" ? : ;
}
else
{
return ;
}
} private static void Put(List<string> bucketBalls, string v)
{
bucketBalls.Add(v);
} private static List<string> Take(List<string> bucketBalls, int v, Random ran)
{
List<string> balls = new List<string>();
int pos;
for (int i = ; i <= v; i++)
{
pos = ran.Next(, bucketBalls.Count());
balls.Add(bucketBalls[pos]);
bucketBalls.RemoveAt(pos);
}
return balls;
}
}
}

通过运行结果可以看出来,概率一直很稳定,为1:

所以答案是在白球和黑球各100个的前提下取球放球,最后都只剩下黑球,概率为1。

修改程序中的初始化参数还可以用来求解课后题中的拓展情况,不用动脑。大家可以试试。

总结过程中遇到的问题:

1、字符串赋值的时候一定要仔细,别写错了!

2、Random.Next()函数返回值的范围包括 minValue 但不包括 maxValue如果 minValue 等于 maxValue,则返回 minValue

C#之桶中取黑白球问题的更多相关文章

  1. 今盒子里有n个小球,A、B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个

    /* 题目描述 今盒子里有n个小球,A.B两人轮流从盒中取球,每个人都可以看到另一个人取了多少个,也可以看到盒中还剩下多少个,并且两人都很聪明,不会做出错误的判断. 我们约定: 每个人从盒子中取出的球 ...

  2. 压缩感知中的lp球:p范数最优化为什么总会导致一个稀疏的解的原因

    转自:彬彬有礼. 压缩感知中的lp球:p范数最优化为什么总会导致一个稀疏的解的原因 http://blog.csdn.net/jbb0523/article/details/40268943 题目: ...

  3. 定时从远程的数据库中取数据,然后把取出来的数据插入或更新本地的oracle数据库的表

    最近项目中有一种需求: 大致需求是这样的 通过给定的 用户名和密码 要定时从远程的数据库中取数据,然后把取出来的数据插入或更新本地的oracle数据库的表 项目的结构式struts1 hibernat ...

  4. LoadRunner中取Request、Response

    LoadRunner中取Request.Response LoadRunner两个“内置变量”: 1.REQUEST,用于提取完整的请求头信息. 2.RESPONSE,用于提取完整的响应头信息. 响应 ...

  5. DataGrid中取HyperLinkColumn列的值,处理DataGrid中绑定的特殊字符

    DataGrid中取HyperLinkColumn列的值. /// <summary> /// 对datagrid中标签进行编码,处理特殊字符 /// </summary> / ...

  6. 【算法与数据结构】在n个数中取第k大的数(基础篇)

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 题目介绍            在n个数中取第k大的数(基础篇),之所以叫基础篇是因为还有很多更高级的算法,这些 ...

  7. Java中取小数点后两位(四种方法)

    摘自http://irobot.iteye.com/blog/285537 Java中取小数点后两位(四种方法)   一 Long是长整型,怎么有小数,是double吧     java.text.D ...

  8. 使用回溯法求所有从n个元素中取m个元素的组合

    不多说了,直接上代码,代码中有注释,应该不难看懂. #include <stdlib.h> #include <stdio.h> typedef char ELE_TYPE; ...

  9. 总结C++中取成员函数地址的几种方法

    这里, 我整理了4种C++中取成员函数地址的方法, 第1,2,4种整理于网上的方法, 第3种cdecl_cast是我自己想到的. 其中, 第4种(汇编)的方法不能在VC6上编译通过. 推荐使用第1,2 ...

随机推荐

  1. zabbix监控企业esxi虚拟机

    zabbix监控企业esxi虚拟机 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我来公司有一段时间了,最近也发现模型部有测试和开发反应某台机器登陆不上去了,结果登陆esxi服务器 ...

  2. Codeforce Round #221 Div2

    每次的CF都是一把辛酸泪! 什么时候能打破这局面,昨天做着睡着了! 有时候有的题目也就差一线! 哎,! A:杠杆原理! B:算最后负的和! B:没弄出来当时就脑短路... C:事后写了个n*log(n ...

  3. codevs 1506 传话

    http://codevs.cn/problem/1506/ 1506 传话  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 白银 Silver 题解       题目描述 D ...

  4. [转]数据库高可用架构(MySQL、Oracle、MongoDB、Redis)

    一.MySQL   MySQL小型高可用架构 方案:MySQL双主.主从 + Keepalived主从自动切换 服务器资源:两台PC Server 优点:架构简单,节省资源 缺点:无法线性扩展,主从失 ...

  5. [原创] 关于quartz (spring 中的任务调度器)时间配置

    1.   CronTrigger时间格式配置说明 CronTrigger配置格式: 格式: [秒] [分] [小时] [日] [月] [周] [年] 序号 说明 是否必填 允许填写的值 允许的通配符 ...

  6. [原创]java WEB学习笔记56:Struts2学习之路---Struts 版本的 登录 demo

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  7. UML: 序列图

    摘自http://www.umlonline.org/school/thread-37-1-1.html 大家都进过餐馆吃饭吧?你是如何和餐厅服务员“眉来眼去”的呢?回忆一下从你进餐馆开始到你离开餐馆 ...

  8. eclipse key

    让我们按照使用频率来看看我最爱用的一些热键组合.(注:以下内容在Eclipse3.02及一上版本通过测试) . Control-Shift-T: 打开类型(Open type).如果你不是有意磨洋工, ...

  9. 关于用php插入汉字到oracle中出现不乱码问题

    $conn = oci_pconnect("IBADMINTON", "5206576360", $db,'utf8'); 在代码中加入‘utf8’即可:   ...

  10. 表单和验证事件以及marquee标签

    1.表单验证<form></form> (1).非空验证(去空格) (2).对比验证(跟一个值对比) (3).范围验证(根据一个范围进行判断) (4).固定格式验证:电话号码, ...