UVa 1638 - Pole Arrangement(dp)
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4513
题意:
有高为1, 2, 3,…, n的杆子各一根排成一行。从左边能看到L根,从右边能看到R根,求有多少种可能。
分析:
设d(i,j,k)表示让高度为1~i的杆子排成一行,从左边能看到j根,从右边能看到k根的方案数(设i≥2)。
按照从大到小的顺序安排各个杆子。假设已经安排完高度为2~i的杆子,
那么高度为1的杆子不管放哪里都不会挡住任何一根杆子。有如下3种情况。
情况1:插到最左边,则从左边能看到它,从右边看不见(因为i≥2)。
情况2:如果插到最右边,则从右边能看到它,从左边看不见。
情况3(有i-2个插入位置):插到中间,则不管从左边还是右边都看不见它。
在第一种情况下,高度为2~i的那些杆子必须满足:从左边能看到j-1根,从右边能看到k根,
因为只有这样,加上高度为1的杆子之后才是“从左边能看到j根,从右边能看到k根”。
虽然状态d(i,j,k)表示的是“让高度为1~i的杆子……”,而现在需要把高度为2~i+1的杆子排成一行,
但是不难发现:其实杆子的具体高度不会影响到结果,只要有i根高度各不相同的杆子,
从左从右看分别能看到j根和k根,方案数就是d(i,j,k)。换句话说,情况1对应的方案数是d(i-1,j-1,k)。
类似地,情况2对应的方案数是d(i-1,j,k-1),而情况3对应的方案数是d(i-1,j,k)*(i-2)。
这样,就得到了如下递推式:d(i,j,k) = d(i-1,j-1,k) + d(i-1,j,k-1) + d(i-1,j,k)*(i-2)。
代码:
1 import java.io.*; 2 import java.util.*; 3 4 public class Main { 5 static final int UP = 20 + 1; 6 static long d[][][] = new long[UP][UP][UP]; 7 8 static void constant() { 9 d[1][1][1] = 1; 10 for(int n = 2; n < UP; n++) { 11 for(int L = 1; L <= n; L++) { 12 for(int R = 1; R <= n; R++) { 13 d[n][L][R] += d[n-1][L-1][R]; 14 d[n][L][R] += d[n-1][L][R-1]; 15 d[n][L][R] += d[n-1][L][R] * (n-2); 16 } 17 } 18 } 19 } 20 21 public static void main(String args[]) { 22 Scanner cin = new Scanner(new BufferedInputStream(System.in)); 23 constant(); 24 25 int T = cin.nextInt(); 26 while(T --> 0) { 27 int n = cin.nextInt(); 28 int L = cin.nextInt(); 29 int R = cin.nextInt(); 30 System.out.println(d[n][L][R]); 31 } 32 cin.close(); 33 } 34 }