JAVA算法练习(10):绳圈

本文介绍了一个有趣的数学问题——绳圈问题,探讨如何计算100根绳子最终形成绳圈的最大概率。通过建立二维数组,分析绳子数量与圈数之间的关系,推导出概率变化的数学规律,并用Java代码实现了解决方案。最终通过遍历计算,找到最大概率对应的圈数并输出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

------文章底部代码分享

 一、题目

标题:绳圈
今有100 根绳子,当然会有200个绳头。
如果任意取绳头两两配对,把所有绳头都打结连接起来。最后会形成若干个绳圈(不考虑是否套在一起)。

我们的问题是:请计算最后将形成多少个绳圈的概率最大?
注意:结果是一个整数,请通过浏览器提交该数字。不要填写多余的内容。

 

二、解题

        这个题在原理上是特别简单,难点在于公式的推演;

2.1

        第一步建立一个二维数组,横坐标存储绳子数量,纵坐标存储组成的圈数,内部存储该绳子数量组成的圈的概率;

        将 1 根绳子组成一个圈的情况赋值 1 ;

 2.2

        直接使用暴力枚举遍历出所有情况下的概率;

 2.3

        因为 概率 = 当前状况的数量 / 所有情况总数 ;

        所以我们主要想办法理出当前状况数量跟所有情况总数的规律;

        

        A.方法总数的规律:

        方法总数[ i-1 ]在增加一根绳子求方法总数[ i ]的时候有两种搭配情况,

        1.方法总数在组成曾组成过的圈数时每增加一个结点的时候相当于每次方法总量自身乘以了 ( 绳子数 - 1 ) ,因为一根线有两个结点,故每增加一根绳子的时候相当于每次方法总量自身乘以了 2 * ( 绳子数 - 1 )

        2.还有一种情况是新增绳子自成圈,即方法总数[ i-1 ]增加一根线时需要增加方法总量[ i-1 ]个情况;

        将 1 、2 组合得到:

        方法总数[ i ] = 方法总数[ i-1 ] * 2 * ( i - 1 ) + 方法总数[ i-1 ];

        化简为:

        方法总数[ i ] = 方法总数[ i-1 ] * ( 2 * i - 1 );

        

        B.圈数为 1 的变化规律:

        1.因为每增加一个结点组成数量就能需要乘以 ( 绳子数 - 1 ) ,而一条绳子有两个结点,故每次绳子数 +1 就需要乘以 2 * ( 绳子数 -1 )倍的数量;

        2.因为 ( 绳子数 -1 情况下组成 1 圈的概率 )  * ( 绳子 -1 情况下的绳子总数 ) = 绳子数 -1 情况下的组成 1 圈的方法量 ,

        故组合为 概率[ i ][ 1 ] =/ 方法总数[ i ];
        将 A 、B 组合得出 概率[ i ][ 1 ] = 概率[ i-1 ][ 1 ] * 方法总数[ i-1 ] * 2 * ( i - 1 ) / 方法总数[ i-1 ] * ( 2 * i - 1 ) ;

        

        C.圈数为 j 时的变化规律:

        1.组成圈数为 j 的情况再加一根绳可以有两种情况,一种是原绳子组成 j - 1 个圈的情况下新增绳子自成一个圈,一种是新增绳子插入到原绳子数组成 j 个圈的情况;

        2.新增绳子自成一圈的情况的计算就相当于原绳子组成 j - 1 个圈的情况的数量,即:

        概率[ i-1 ][ j-1 ] * 方法总数[ i-1 ];

        3.参考 B 可以得出,增加一根绳子插入可得到的数量为:

         概率[ i-1 ][ j ] * 方法总数[ i-1 ] * 2 * ( i - 1 );

        

        D.将 A、C 组合起来为:

        概率[ i-1 ][ j-1 ] * 方法总数[ i-1 ] + 概率[ i-1 ][ j ] * 方法总数[ i-1 ] * 2 * ( i - 1 ) / 方法总数[ i-1 ] * ( 2 * i - 1 ) ;

        将分子分母中共有的方法总数[ i-1 ]化简,得到:

        概率[ i ][ j ] = 概率[ i-1 ][ j-1 ] + 概率[ i-1 ][ j ] * 2 * ( i - 1 ) / ( 2 * i - 1 ) ;

        

        将公式写入遍历内:

2.4

        声明两个变量一个存储 100 根绳子组成 x 个圈的概率,一个存储所存概率是的 x 圈数;

        通过遍历将最大的圈数概率选取出来,最后输出圈数;

 

三、代码分享

public class Main {
    public static void main(String[] args) {
        double[][] arr = new double[101][101];
        arr[1][1] = 1;

        int i , j;
        for ( i = 2; i < 101; i++ )
            for ( j = 1; j <= i; j++ ){
                arr[i][j] = ( arr[i-1][j] * 2 * ( i - 1 ) + arr[i-1][j-1] ) / ( 2 * i - 1 );
            }
        double prob = arr[100][1];
        int num = 1;
        for ( i = 2 ; i < 101 ; i++ ){
            if ( prob < arr[100][i] ){
                prob = arr[100][i];
                num = i;
            }
        }
        System.out.println( num );
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jc_caterpillar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值