[LeetCode 1,223] 주사위 던지기 시뮬레이션

다이 시뮬레이터 각 롤 1~6에서 난수를 생성한다. 당신은 수 롤백 할 수 없습니다 있도록 발전기에 제약을 도입  i 보다  rollMax[i] (1 인덱스) 번 연속. 

정수 배열을 감안  rollMax 하고 정수  n, 정확하게 얻을 수있다 고유 시퀀스의 수 복귀  n 롤.

적어도 하나 개의 원소가 서로 다르면 두 시퀀스는 상이한 것으로 간주된다. 대답은 너무 큰 수 있기 때문에, 그것을 모듈을 반환합니다  10^9 + 7.

 

예 1 :

입력 : N = 2 ROLLMAX = [1,1,2,2,2,3] 
출력 : 34 
명 : 다이에 아무런 제약이없는 경우가 있으며, 다이 롤 (2)이있을 것이다 6 * 6 = 36 가능한 조합. 이 경우, ROLLMAX 어레이를 찾고, 숫자 1과 2는 따라서 순서 (1,1) 및 (2,2)가 발생할 수없는 최대 회 연속적으로 표시되므로, 최종 응답은 36-2 = 34이다.

예 2 :

입력 : N = 2 ROLLMAX = [1,1,1,1,1,1] 
출력 : 30

예 3 :

입력 : N = 3 ROLLMAX = [1,1,1,2,2,3] 
출력 : 181

 

제약 :

  • 1 <= n <= 5000
  • rollMax.length == 6
  • 1 <= rollMax[i] <= 15

 

동적 프로그래밍 솔루션 (1)

주 정의 : DP [I] [J] : 상기 마지막 번호 인 I와 J 롤의 다른 시퀀스의 총 수. 초기화 : J에 대한 DP [1] [J] = 1, [0, 5]. (0 인덱스에 매핑 1 인덱스). 답 : DP [N]의 합에 대한 J [J] [0, 5].

상태 전이 분석 : DP [I] [J]의 두 가지 경우가있을 수있다 : 하나의 마지막 압연 번호는 이전 번호가 상이한 또는 이전과 동일하다.

첫 번째 경우에있어서, 단순히 0 내지 5 J를 반복하고 모든 DP 추가 [I - 1 [K]는 K = J가 [I] [J]를 DP 어디!. 

두 번째 경우, 우리는 일본의 두 개의 연속 압연 번호가 이미 있다는 것을 알고있다. 우리는 대부분의 ROLLMAX [J] 연속 J에서 할 수 있습니다. ROLLMAX [j]가 15 이하인 때문에, 우리는 2, 3, 4 ... ROLLMAX [J] 연속 J 끝나는 모든 서열을 추가 할 수있다. 

그렇게에서 몇 가지 핵심 포인트 : 

J의 고정 된 연속 번호 1, 우리는 모든 DP를 추가 할 필요가, CNT 말 [I - CNT] [t] 여기서 t = J!. 이는 탄소 나노 튜브의 정확한 연속 J로 끝나는 모든 시퀀스를 나타냅니다. 

2. 합계를 종료 두 가지 시나리오가있다. 어느 우리 ROLLMAX [J]의 한계를 초과하거나 우리 롤의 부족, 즉, 롤의 현재 수는 <= ROLLMAX [J]이다. ROLLMAX [J]를 초과하는 경우, 단순히 중지; 우리가 롤 아웃 인 경우, 우리는 난 경우 모두 롤 전체 JS를 계산 DP에 [I] [J]를 1을 추가 할 필요가있다. 우리가 공 롤이있을 때, 우리가 선택할 수있는 J와 다른 다른 5 개 개의 번호를 가지고 있지 않기 때문입니다. 그것은 단지 그것에서 J를 가지고 한 순서입니다.

 

런타임은 O이다 (N * 6 * 15 * 6). 공간 복잡도는 O이다 (N * 6).

 

실수했다 : 최종 결과 입술을 합산하면 입술을 사용 = (DP 입술 + [N] [I]) 개조 %; 입술 + DP = [N] [i]를 개조 %; 이 업데이트 된 입술의 모듈러 연산을 적용하지 않기 때문에 올바르지 만 각 DP [n]은 [I]에 %를 적용한다. 

 

클래스 해결 {
     공개  INT dieSimulator ( INT의 n은, 값 int [] ROLLMAX) {
         INT 개조 = ( INT ) + 1E9 (7) ;
         DP [] [] = 새로운   [N + 1] [6 ]
         입술 = 0 ; 

        Arrays.fill (DP [ 1], 1 ); 

        위한 ( int로 I = 2; 나는 = <N; i가 ++ ) {
              ( INT의 J = 0; J <6; J ++ ) {
                  ( INT에서 K = 0; K <6; 케이 ++) {
                     경우 (j =! K) { 
                        DP [I] [J] = (DP [I] [J] + DP [내가 - 1 [K]) %의 모드; 
                    } 
                    다른 {
                         INT의 CNT = 2 ;
                         (; CNT <= ROLLMAX [J] && CNT <I; CNT ++ ) {
                              ( INT의 t = 0; t <6; t ++ ) {
                                 경우 (t에서의 == J)가 {
                                     계속 ; 
                                } 
                                DP [I] [J]= (DP [I] [J] + DP [I - CNT] [t]) %의 모드; 
                            } 
                        } 
                        경우 (CNT <= ROLLMAX [J] && CNT == I) { 
                            DP [I] [J] = (DP [I] [J] + 1) % 개조; 
                        } 
                    } 
                } 
            } 
        } 
        에 대해 ( int로 ; I <6, I = 0 난 ++ ) { 
            입술 = (DP 입술 + [N] [I]) % 개조; 
        } 
        리턴 ( INT ) 입술을; 
    } 
}

 

 

동적 프로그래밍 용액 2.

주 : 차원 배열을 선언 DP [2] [6] [16]. 제 1 회 차원은 우리가 하나 더 주사위 롤의 현재 반복을 calcuate하기 위해 이전의 연산 결과를 사용하는 것처럼 롤링 인덱스입니다. 제 2 치수는 지난 압연 수를 나타내며 3 dimenstion은 지난 압연 수의 연속적인 시간을 나타냅니다. 여기에 3 차원은 0 ~ 15 포함에서입니다. 0 전류 수가 최종 압연 수 없다 따라서는 연속적인 시간이 0 있도록 마지막 롤, 다른 번호를 얻을 수 있음을 의미한다.

 

우리가 하나 더 주사위 롤을 때마다, 우리는 모든 가능한 시퀀스 카운트의 현재 상태를 나타내는 새로운 2D 배열을 계산한다. 그래서 외부 루프는 n으로 2에서 이동합니다. 우리는 다음과 같이 내부 :

1. 계산 될 새로운 2D 어레이를 초기화.

1 이상의 롤 숫자 t를 생성하는 경우 연속 시간 J의 난 각 번호 2, 즉 난 DP [(K + 1) % 2] [t] [1] + = DP [K % 2] [아니다 I] [J] 만약 t == 난 후 우리 ROLLMAX [t], DP의 한도를 초과하지 않은 경우 [(케이 + 1) % 2] [t] [J + 1] + = DP [K % 2] [t] [제이]. 

 

초기화 : 1 롤, 회 연속 1의 각 번호 1 개 순서가있다.

답변 : 모든 순서는 J의 0 ~ 15 회 연속으로 1에서 6까지 숫자 J에서 끝나야합니다. 그래서 최종 답변은 마지막으로 계산 된 2 차원 배열의 단지 합계입니다.

 

클래스 해결 {
     공개  INT dieSimulator ( INT의 n은, 값 int [] ROLLMAX) {
         INT 개조 = ( INT ) + 1E9 (7) ;
         입술 = 0 ;
         [] [] [] DP = 새로운   [2] [6] [16 ]; 
        
        // INIT : 연속 1 시간 압연 번호 1 롤 
        위해 ( int로 ; I <6, I = 0 난 ++ ) { 
            DP [ 0] [i]는 [1] = 1 ; 
        } 
        
        // DP [(K + 1) % 2] [I] [J] DP보다 1 이상의 롤을 갖는다 K % 2] [I] [J] 
         (INT의 K = 2; K <= N; K ++ ) {
             // 재 초기화 DP [(K + 1) % 2]를 계산하기 전에 
            대한 ( INT를 p = 0; p <6; P ++ ) { 
                Arrays.fill (DP [(K + 1) % 2] P, 0 ); 
            }             
            에 대해 ( int로 내가 6 <; I = 0 난 ++ ) {
                 위해 ( INT의 J = 0; J ++ <= 15 J ) {
                     // 1 이상의 롤이 어떤 숫자가 될 수 
                     ( INT의 t = 0; t <6 ; t ++ ) {
                         경우 ! (t = I) {
                            DP [(K+ 1) % 2] [t] [1] = (DP [(K + 1) % 2] [t] [1] + DP [% K 2] [I] [J]) % 개조; 
                        } 
                        다른  경우 (j + 1 <= ROLLMAX [t]) { 
                            DP [(K + 1) % 2] [t] [J + 1] = (DP [(K + 1) % 2] [t] [J + 1] + DP [% K 2] [t] [J]) %를 개조하는 단계; 
                        } 
                    } 
                } 
            } 
        } 
        
        // 합까지의 모든 시퀀스 
        길이 [] [] resDp DP = [(N + 1) % 2 ];
        위한 ( int로 ; I <6, I = 0 난 ++ ) {
             위해 ( INT의 ) {J = 0; J <= 15; j 개의 ++의
                입술 = (입술 resDp + [I] [J]) %의 모드; 
            } 
        } 
        리턴 ( INT ) 입술을; 
    } 
}

 

추천

출처www.cnblogs.com/lz87/p/11669196.html