import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StreamTokenizer; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StreamTokenizer in = new StreamTokenizer(br); PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out)); while (in.nextToken() != StreamTokenizer.TT_EOF) { int n = (int) in.nval; in.nextToken(); int m = (int) in.nval; long[][] dp = new long[n + 1][m + 1]; for (int i = 0; i <= n; i++) { for (int j = 0; j <= m; j++) { dp[i][j] = -1; } } out.println(compute2(n, m, dp)); } out.flush(); out.close(); br.close(); } // 记忆化搜索动态规划 private static long compute(int n, int m, long[][] dp) { if (n == 0) { return 1; } if (m == 0) { return 0; } if (dp[n][m] != -1) { return dp[n][m]; } long ans = 0; for (int i = 0; i < n; i++) { ans = (ans + compute(i, m - 1, dp) * compute(n - i - 1, m - 1, dp)) % 1000000007; } dp[n][m] = ans; return ans; } // 严格位置依赖的动态规划 private static long compute2(int n, int m, long[][] dp) { for (int j = 0; j <= n; j++) { dp[j][0] = 0; } for(int i=0; i<= m; i++){ dp[0][i] = 1; } for(int i=1; i<= n; i++){ for(int j=1; j<=m; j++){ dp[i][j] = 0; for(int k=0; k < i; k++) { dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-k-1][j-1]%1000000007)%1000000007; } } } return dp[n][m]; } }