黑马程序员技术交流社区

标题: 抽奖概率问题,答对了有黑马币!! [打印本页]

作者: 酱油    时间: 2016-2-1 20:12
标题: 抽奖概率问题,答对了有黑马币!!
本帖最后由 酱油 于 2016-2-13 20:16 编辑

过年了,黑马为学生们举行了一次抽奖活动,规则如下:
      首先,所有参加抽奖的的人都将一张写有自己名字的字条放入抽奖箱中;
      然后,待所有字条加入完毕,每人从箱中取一个字条;
      最后,如果取得的字条上写的就是自己的名字,那么就表示中奖了!
但是。悲剧的是,最后却发现现场的所有人都没有中奖,。。。
好的,那么问题来了,请用编写程序计算一下,发生这种情况的概率是多少?
问题要求:用键盘输入一个整数P表示参加抽奖活动的人数。
          程序运行,输出结果为所有人都没中奖的概率。用百分号表示,四舍五入保留两位小数。
          如输入2,结果运行输出答案应该是50.00%

答题要求:1、写出解题思路。
                  2、运行截图,输出结果按照题中要求
                  3、不得百度、抄袭,如有发现,,,没有分哦
                   4、答对经过审核者,可获得10个黑马币





作者: 洋葱头头    时间: 2016-2-1 21:02
概率是0
作者: 酱油    时间: 2016-2-1 21:04
洋葱头头 发表于 2016-2-1 21:02
概率是0

我要举报洋葱刷分!
作者: 西贝    时间: 2016-2-1 23:33
好难啊,像我这种半路出家的,看个排序的算法都得半天,这题估计是搞不定了
作者: 酱油    时间: 2016-2-1 23:36
西贝 发表于 2016-2-1 23:33
好难啊,像我这种半路出家的,看个排序的算法都得半天,这题估计是搞不定了 ...

是要考一点思维,,不过写程序就是要锻炼思维。我觉得这种题,平时接触接触也挺好的,我提示一下吧,属于排列组合的数学问题。
作者: Bobby1109    时间: 2016-2-2 00:26
本帖最后由 Bobby1109 于 2016-2-2 00:32 编辑

思路:总的来讲,先列出所有可能情况,逐一对每一种情况检查,删除不符合要求的情况。最后用符合要求情况数量除以所有可能情况数量得到概率。
具体如下:
1. 事件模型:
创建一个元素类型为Integer的List集合aList。并利用for循环为每个元素赋值。
将参与抽奖的每个人视为集合中的每个元素。一个人抽中奖可理解为元素的值和元素的索引相同。

2. 列出所有可能情况:
在while循环中利用Collections.shuffle(aList) 对元素进行排列,每排一次就把aList中的元素转为String elemStr(元素间空格分开),并把elemStr存入TreeSet resultSet中。当resultSet的大小为抽奖人数P的阶乘时,循环停止。至此,resultSet中的元素为所有可能情况。

3. 删除不符合要求的情况:
遍历resultSet,如果某元素第i位上的数值为i,表示该人抽到自己的名字,则删除该元素。即删除抽到自己的情况。

4. 输出结果:
double result = resultList.size()*1.0/P! * 100;
将 result 转为字符串后截取小数点后两位的字符串作为子字符串并加上% 输出至控制台即可。

输出结果格式图片:
               




作者: 酱油    时间: 2016-2-2 11:58
Bobby1109 发表于 2016-2-2 00:26
思路:总的来讲,先列出所有可能情况,逐一对每一种情况检查,删除不符合要求的情况。最后用符合要求情况数 ...

代码一起贴上看看。
作者: youngrivers    时间: 2016-2-5 01:15
中奖 概率是1/P,你在逗我,这个有什么好编程计算的
作者: youngrivers    时间: 2016-2-5 01:17
youngrivers 发表于 2016-2-5 01:15
中奖 概率是1/P,你在逗我,这个有什么好编程计算的

这个属于概率学最基础的东西了
作者: 酱油    时间: 2016-2-5 11:09
youngrivers 发表于 2016-2-5 01:17
这个属于概率学最基础的东西了

呵呵 麻烦先看清题意 我可没让你求中奖的概率  

作者: wusiyi    时间: 2016-2-13 17:38
附件Test.zip直接改名成Test.java。
下面是代码和截图,附件中也是代码和截图。
楼主快赏我!!!{:2_32:}
/*
1、获取用户输入的人数;
2、判断输入的人数,如果为1,说明0.00%的概论都抽不中;如果大于1,则运行运算;如果都不是则提示输入错误;
3、根据规律,都抽不中的概率为(x-1)!/(x!),计算都抽不中的概率;
4、通过四舍五入化为四位数的整数result;
5、a为小数点前两位数,即result除以100的商;
6、b为小数点后两位数,如果b的长度为1,那么结果应为0x,因此,在b前在连上一个0;
7、打印输出a与b连接后的字符串并加上%号;
*/

import java.util.Scanner;
class Test {
public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
  System.out.println("请输入人数:");
  int num = sc.nextInt();
  double x = 1;
  if (num == 1) {
   System.out.println("0.00%");
  } else if (num > 1) {
   for (int i = num; i > 1; i--) {
    x *= ((i - 1) / (i * 1.0));
   }
   long result = Math.round(x * 10000);
   
   String a = (result / 100) + "";
   String b = (result % 100) + "";
   
   if(b.length() == 1) {
    b = "0" + b;
   }
   
   System.out.println("所有人都没中奖的概论为:" + a + "." + b + "%");
  } else {
   System.out.println("输入的人数有误!");
  }
}
}


Test.zip (1.06 KB, 下载次数: 186)

QQ截图20160213173314.png (78.6 KB, 下载次数: 49)

QQ截图20160213173314.png

作者: 酱油    时间: 2016-2-13 19:16
wusiyi 发表于 2016-2-13 17:38
附件Test.zip直接改名成Test.java。
下面是代码和截图,附件中也是代码和截图。
楼主快赏我!!!

没怎么看懂你的思路,,不过,我验证了一下你的结果,是错的。给你看一下我测试的数据吧,这是我原来在oj网站上做的题,AC了的,所以数据是肯定准确的,当然你也可以用数学概率来算,10以内的人数,来验证你自己的程序结果是不是对的。你再考虑考虑吧,找的规律应该不对,还有你的保留两位小数的方法,有些麻烦了,java有很多种方法直接保留两位小数,你可以去百度看一下。你可以继续做,过两天给你分,,加油、PS:图片上,第一行是我输入的测试数据组数。后面没两行为一组数据,第一行表示人数,第二行表示概率。

}WAK$MKE~N7ZO(SU$1EEC9E.png (16.7 KB, 下载次数: 31)

}WAK$MKE~N7ZO(SU$1EEC9E.png

作者: 酱油    时间: 2016-2-13 20:17
酱油 发表于 2016-2-13 19:16
没怎么看懂你的思路,,不过,我验证了一下你的结果,是错的。给你看一下我测试的数据吧,这是我原来在oj ...

我把权限取消了。。
作者: 酱油    时间: 2016-2-13 20:18
wusiyi 发表于 2016-2-13 17:38
附件Test.zip直接改名成Test.java。
下面是代码和截图,附件中也是代码和截图。
楼主快赏我!!!

权限取消了
作者: wusiyi    时间: 2016-2-13 20:33
酱油 发表于 2016-2-13 19:16
没怎么看懂你的思路,,不过,我验证了一下你的结果,是错的。给你看一下我测试的数据吧,这是我原来在oj ...

你的结果中,从7开始概率就没变了耶。。。
作者: wusiyi    时间: 2016-2-13 20:38
youngrivers 发表于 2016-2-5 01:15
中奖 概率是1/P,你在逗我,这个有什么好编程计算的

嗯,楼主,概率确实是1/P.
如果有P人,那么第一个人抽不中的概率为P-1/P;
第二个人抽的时候只剩下P-1,所以第二个人抽中的概率为P-1-1/P-1;
.....
然后倒数第二个人抽的时候1/2;
所以就是(P-1)!/P!
所以就是1/P。
楼主给分呗。
作者: 酱油    时间: 2016-2-13 20:45
wusiyi 发表于 2016-2-13 20:38
嗯,楼主,概率确实是1/P.
如果有P人,那么第一个人抽不中的概率为P-1/P;
第二个人抽的时候只剩下P-1,所 ...

,,,,你认真看了么?说的是所有人都不中奖的概率 ,,你觉得会是1/P ?你也跟着他一起来逗我了?
作者: 酱油    时间: 2016-2-13 20:54
wusiyi 发表于 2016-2-13 20:33
你的结果中,从7开始概率就没变了耶。。。

因为这种问题当人数多了以后,所有人不中奖的发生概率就会变小,我这里是保留的2位小数,所以7以后基本变化都不大了。给你看一张另外的截图,,基本到了20以后概率就趋近于0了,,,(还有这道题,在数学里面是 属于 错排列问题,,有一个公式很简单解决这类问题。。。。是不是感觉被坑了?。、。。

Z~CK}P{CG~GK9P5D@DAYOQ6.png (37.57 KB, 下载次数: 51)

Z~CK}P{CG~GK9P5D@DAYOQ6.png

作者: wusiyi    时间: 2016-2-13 21:03
酱油 发表于 2016-2-13 20:54
因为这种问题当人数多了以后,所有人不中奖的发生概率就会变小,我这里是保留的2位小数,所以7以后基本变 ...

关键是20的时候还是36%,到21就趋近于0%,这不科学!
作者: wusiyi    时间: 2016-2-13 21:09
我再想想看看。。。
作者: boboyuwu    时间: 2016-2-13 21:17
代码:
import java.util.Scanner;
class GaiLv
{
        public static void main(String []args) {
                System.out.println("请输入参与抽奖的人数");
                Scanner scanner=new Scanner(System.in);
        int num=scanner.nextInt();
                float n=num;
                float g=0;
                float sum=0;
        for(float i=0;i<num;i++) {
                  g=1-1/(n-i);
                  sum=sum+g;
                }
        }
}


思路

1.思路
假设总共有n个人抽奖,第一个抽不中自己的概率是1-(1/n),第二个抽不中自己的概率是1-(1/n-1),第三个就是
1-(1/n-2)...第n-1个抽不中概率是
1/2,第n个抽不中概率是0
最后所有求到的概率相加
作者: boboyuwu    时间: 2016-2-13 21:57
反正你出概率的题我就不想做了 高中概率没及格过
作者: wusiyi    时间: 2016-2-13 22:23

我网上找了一下公式,发现确实是你的那个答案,不过21的时候并不是趋近于0。我也想通了我原来的想法哪里出问题了,哈哈。
作者: wusiyi    时间: 2016-2-13 23:06
boboyuwu 发表于 2016-2-13 21:57
反正你出概率的题我就不想做了 高中概率没及格过

你都那么多分了,不做也行了。赏我点{:2_38:}
作者: wusiyi    时间: 2016-2-13 23:07
wusiyi 发表于 2016-2-13 22:23
我网上找了一下公式,发现确实是你的那个答案,不过21的时候并不是趋近于0。我也想通了我原来的想法哪里出 ...

楼主,这个公式也做出来了,分就给我把。啊哈哈。
作者: wusiyi    时间: 2016-2-13 23:10
boboyuwu 发表于 2016-2-13 21:17
代码:
import java.util.Scanner;
class GaiLv

啊哈哈,这想法是错的,我之前也是这么想的。
作者: 酱油    时间: 2016-2-15 21:30
wusiyi 发表于 2016-2-13 23:07
楼主,这个公式也做出来了,分就给我把。啊哈哈。

我让洋葱给你分了。。。
作者: yindalei00    时间: 2016-2-15 23:25
本帖最后由 yindalei00 于 2016-2-16 00:14 编辑

都未中奖概率   初中学的还给老师了        占楼编辑概率是硬伤 初学不易
import java.util.Scanner;
public class Test1 {
        public static void main(String[] args) {
                System.out.println("请输入参与抽奖的人数");
                Scanner PP=new Scanner(System.in);
                float p=PP.nextFloat();
                double chance;
                //double chance= "!!!求中奖概率!!!!!";
                chance*=100;       
                System.out.printf("所有人都没中奖的概率为%.2f",chance);
                System.out.println("%");
                }
}


作者: wusiyi    时间: 2016-2-16 10:36
酱油 发表于 2016-2-15 21:30
我让洋葱给你分了。。。

{:2_32:}楼主你真棒!哈哈。
作者: j6819236    时间: 2016-2-17 10:43
本帖最后由 j6819236 于 2016-2-17 10:45 编辑

概率公用程序直接写上去貌似有点简单,所以用递归模拟了下这个过程。
根据概率定义写的,算出事件总数sum,再算出每个人都抽不到自己的事件数signal, signal/sum就是所求概率
假设有n个人,n就代表第n个人的名字,可以用集合模拟,只要第n个人不抽到数字n也就是不抽到自己,
例如有4个人, 3,2,1,0 对应抽到的名字 0,1,2,3这就算一种情况,用递归先抽第n个人的卡片,接着n-1,直到第1个人
。但是貌似这样内存有点吃不消,有人能帮忙修改下吗,实在没办法优化。
  1. package com.heima;

  2. import java.util.ArrayList;
  3. import java.util.Scanner;

  4. /*问题要求:用键盘输入一个整数P表示参加抽奖活动的人数。
  5. 程序运行,输出结果为所有人都没中奖的概率。用百分号表示,四舍五入保留两位小数。
  6. 如输入2,结果运行输出答案应该是50.00%*/

  7. //总的思路,就使用集合模拟抽取过程,用集合索引n对应第n个人,集合中元素则装载着对应卡片
  8. public class Test10 {
  9.         // 装载抽不到自己名字卡片的组合集合
  10.         static ArrayList<Integer> list = new ArrayList<>();

  11.         public static void main(String[] args) {
  12.                 Scanner sc = new Scanner(System.in);
  13.                 System.out.println("请输入参加活动人数:");
  14.                 while (true) {
  15.                         int n = sc.nextInt();
  16.                         ArrayList<Integer> arr = new ArrayList<>();
  17.                         // 模拟抽奖盒子有n张卡片,把n张卡片一一对应添加进集合arr,从0开始
  18.                         init(arr, n);
  19.                         // 是否打印所有抽不到自己名字卡片的排列组合
  20.                         System.out.println("请选择是否打印结果('1'为'是'):");
  21.                         int print = sc.nextInt();
  22.                         // 计算所有人都抽不到自己名字卡片概率并精确到指定精度
  23.                         double pro = (double) eventNotSelf(arr, print) / (double) eventSum(arr);
  24.                         StringBuffer strPro = new StringBuffer(String.valueOf(Math.round(pro * 10000)));
  25.                         System.out.println("所有人都没中奖概率:" + strPro.insert(2, ".") + "%");
  26.                 }
  27.         }

  28.         // 模拟把n张卡片装进抽奖盒子
  29.         public static void init(ArrayList<Integer> arr, int n) {

  30.                 for (int i = 0; i < n; i++) {
  31.                         arr.add(i);
  32.                 }
  33.         }

  34.         // 计算n个人不放回地从盒子中抽1张卡片事件数总和
  35.         public static int eventSum(ArrayList<Integer> arr) {
  36.                 int count = 0;
  37.                 // 卡片全抽完,事件数总和加1
  38.                 if (arr.size() == 1) {
  39.                         return 1;
  40.                 }
  41.                 // 模拟卡片抽取,第arr.size个人可以抽取盒子当前任意卡片,每种可能都要计算
  42.                 for (int i = 0; i < arr.size(); i++) {
  43.                         // 第arr.size个人拿出写着arr.get(i)名字卡片
  44.                         int temp = arr.get(i);
  45.                         // 盒子中去除此卡片
  46.                         arr.remove(i);
  47.                         // 第arr.size-1个人拿盒子中剩余的卡片,事件总数累加
  48.                         count = count + eventSum(arr);
  49.                         // 回到第arr.size个人,他还有可能抽写着非arr.get(i)名字卡片,所以放回arr.get(i)卡片,抽其他人名字卡片
  50.                         arr.add(i, temp);
  51.                 }
  52.                 // 返回事件总和数
  53.                 return count;
  54.         }

  55.         // 抽不到自己名字卡片的事件总和数,print=1打印每个人对应抽到的卡片
  56.         public static int eventNotSelf(ArrayList<Integer> arr, int print) {
  57.                 int count = 0;
  58.                 // 模拟卡片抽取,第arr.size个人可以抽取盒子当前任意非自己名字卡片,每种可能都要计算
  59.                 for (int i = 0; i < arr.size(); i++) {
  60.                         // 第arr.size个人拿出写着arr.get(i)名字卡片
  61.                         int temp = arr.get(i);
  62.                         // 第arr.szie个人没拿到写着自己名字的卡片
  63.                         if (temp != arr.size() - 1) {
  64.                                 // 装载入list
  65.                                 list.add(temp);
  66.                                 // 如果是最后一个人,符合事件要求,每个人都没拿到自己名字卡片,事件数总和加1
  67.                                 if (arr.size() == 1) {
  68.                                         // 是否打印每个人抽的的卡片
  69.                                         if (print == 1)
  70.                                                 System.out.println(list);
  71.                                         count = 1;
  72.                                         // 如果不是最后一个人,则接着抽取盒子中卡片
  73.                                 } else {
  74.                                         // 首先从盒子中抽走arr.get(i)名字卡片
  75.                                         arr.remove(i);
  76.                                         // 第arr.size-1个人接着抽盒子剩余卡片,事件数总和累加
  77.                                         count = count + eventNotSelf(arr, print);
  78.                                         // 因为 第arr.size个人还有可能抽到非arr.get(i)名字卡片,所以放回卡片重新抽下一张
  79.                                         arr.add(i, temp);
  80.                                 }
  81.                                 // 进入下一种情况,清除上一种情况
  82.                                 list.remove(list.size() - 1);
  83.                         }
  84.                 }
  85.                 return count;

  86.         }

  87. }
复制代码



作者: feimingxuan    时间: 2016-6-15 01:03
666666666666666666666




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2