当前位置:首页 » Project Euler » 详细页

Counting block combinations II 题号:115 难度: 35 中英对照

NOTE: This is a more difficult version of Problem 114.

A row measuring n units in length has red blocks with a minimum length of m units placed on it, such that any two red blocks (which are allowed to be different lengths) are separated by at least one black square.

Let the fill-count function, F(m, n), represent the number of ways that a row can be filled.

For example, F(3, 29) = 673135 and F(3, 30) = 1089155.

That is, for m = 3, it can be seen that n = 30 is the smallest value for which the fill-count function first exceeds one million.

In the same way, for m = 10, it can be verified that F(10, 56) = 880711 and F(10, 57) = 1148904, so n = 57 is the least value for which the fill-count function first exceeds one million.

For m = 50, find the least value of n for which the fill-count function first exceeds one million.

Solution

动态规划。 考虑$dp[i][j]$,表示长度为$i$时,左侧为黑色($j=0$)或者红色($j=1$)时的答案。 初始条件为:$i< 50$,$dp[i][0]=1,dp[i][1]=0$。对于$dp[50][0]=dp[50][1]=1$。 递推为: 1. 计算$dp[i][0]$,则左侧为黑色,可以放一个黑色块,右侧$i-1$的空间随便填,即为$dp[i-1][0]+dp[i-1][1]$。 2. 计算$dp[i][1]$,则左侧为红色,可以考虑枚举左侧红色块的长度为$j$,那么剩下部分需要填入左侧为黑色的$dp[i-j][0]$。

Code


public final class p115 {
    public static void main(String[] args) {
        long start=System.nanoTime();
        String result = run();        
        long end=System.nanoTime();
        System.out.println(result);
        System.out.println( (end-start)/1000000 + "ms" );
    }
    
    static public long dp[][]=new long[200][2];
    static public String run(){
    	for(int i=0;i<50;i++){
    		dp[i][0]=1;
    		dp[i][1]=0;
    	}
    	dp[50][0]=1;//black
    	dp[50][1]=1;//red
    	for(int i=51;i<200;i++){
    		dp[i][0]=dp[i-1][0]+dp[i-1][1];
    		dp[i][1]=0;
    		for(int j=50;j<=i;j++)
    			dp[i][1]+=dp[i-j][0];
    		if(dp[i][0]+dp[i][1]>1000000){
    			return Integer.toString(i);
    		}
    	}
    	return null;
    }
    
}
168
0ms