------文章底部代码分享
一、题目
标题:绳圈
今有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 );
}
}