import java.util.Scanner; public class Main { //网格走法数目 public static void main(String[] args) { Scanner in = new Scanner(System.in); int m,n; m = in.nextInt(); n = in.nextInt(); int f[][] = new int[11][11]; f[0][0] = 0; for(int i=0; i<=m; i++) f[i][0] = 1; for(int i=0; i<=n; i++) f[0][i] = 1; for(int i=1; i<=m; i++){ for(int j=1; j<=n; j++) f[i][j] = f[i-1][j] + f[i][j-1]; } System.out.print(f[m][n]); } }
非常经典的动态规划 做过很多变种 这个是最简单的类型
要注意题目的意思 x y是格点 所以都要加一
#include<iostream>
using namespace std;
int dp[15][15];
int main(){
int x, y;
scanf("%d%d", &x, &y);
for(int i = 1; i <= x + 1; i++) dp[i][1] = 1;
for(int i = 1; i <= y + 1; i++) dp[1][i] = 1;
for(int i = 2; i <= x + 1; i++)
for(int j = 2; j <= y + 1; j++)
dp[i][j] = dp[i-1][j] + dp[i][j-1];
printf("%d\n", dp[x+1][y+1]);
}
import java.util.*; public class Main{ public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x = sc.nextInt(); int y = sc.nextInt(); int[][] fcount = new int[x+1][y+1]; for(int i = 0 ; i <= x;i++) { fcount[i][0] = 1; } for(int i = 0; i <= y;i++) { fcount[0][i] = 1; } for(int i = 1;i <= x;i++) { for(int j = 1;j <= y;j++) { fcount[i][j] = fcount[i-1][j] + fcount[i][j-1]; } } System.out.println(fcount[x][y]); } }
import java.util.Scanner; public class Main{
// 直接C(n+m,n) public static void main(String[] args) { Scanner sc = new Scanner(System.in); long n = sc.nextInt(); long m = sc.nextInt(); System.out.println(recursive_C(n + m, m)); } // C(n,m) public static long recursive_C(long n, long m) { return getNFactorial(n) / getNFactorial(m) / getNFactorial(n - m); } // n! public static long getNFactorial(long n) { if (n == 0) { return 1; } return n * getNFactorial(n - 1); } }
#include <iostream>
using namespace std;
long long int factorial(int m);
int main(int argc, const char * argv[])
{
int x,y;
cin>>x>>y;
long long int ways;
ways=factorial(x+y)/(factorial(x)*factorial(y));
cout<<ways;
}
long long int factorial(int m)
{
long long int total=1;
int i=1;
for(;i<=m;i++)
{
total=total*i;
}
return total;
}
while(line = readline()){ var lines = line.split(' '); var a = parseInt(lines[0]), b = parseInt(lines[1]); function cellCount(x,y){ var arr =[]; //每个格点初始化为1 for(var i=0; i<=x;i++){ arr[i]=[]; for(var j=0; j<=y;j++){ arr[i][j] = 1; } } //每个格点的值是其左边和上边格点值的和 for(var i=1;i<=x;i++){ for(var j=1;j<=y;j++){ arr[i][j] = arr[i-1][j] + arr[i][j-1]; } } return arr[x][y]; } print(cellCount(a,b)); }
两个思路,一种动态规划,一种是递归,其实原理都是一样的。 都是通过状态转移方程找到边界条件来求解。
可以看出网格中的到达网格中的任意一点的状态方程为: d(m,n)=d(m-1,n)+d(m,n-1)
也就是到达相邻的左节点和上节点的所有路线的和
边界条件:到达所有处于第一行跟第一列的所有的点的路线都只有一条。
知道了状态方程跟 边界条件,那么我们就可以使用动态规划来解决了;
这里附上两个解法,第一个是动态规划,第二个是递归
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { int m = sc.nextInt(); int n = sc.nextInt(); //动态规划 System.out.println(dpHandle(init(m, n),m, n)); //递归 //System.out.println(recursiveHandle(init(m, n), m, n)); } } public static int dpHandle( int[][] a ,int m, int n) { for (int i = 1; i < a.length; i++) { for (int j = 1; j < a[i].length; j++) { a[i][j] = a[i - 1][j] + a[i][j - 1]; } } return a[m][n]; } public static int[][] init(int m, int n) { int[][] a = new int[m + 1][n + 1]; for (int i = 0; i < a[0].length; i++) { a[0][i] = 1; } for (int i = 0; i < a.length; i++) { a[i][0] = 1; } return a; } public static int recursiveHandle(int[][] a, int m, int n) { if (m == 0 && n == 0) { return 0; } if (m == 0 || n == 0) { return 1; } return recursiveHandle(a, m - 1, n) + recursiveHandle(a, m, n - 1); } }
解题思路:Nx1的网格 以及 1xN的网格都遵循 起点到终点的方法数为:N+1,其他点等于“肩上”两个网格的和,所有算法采用递归实现
import sys
net = sys.stdin.readline().split()
x = int(net[0])
y = int(net[1])
def rec(x,y):
if(x==1)or(y==1):
return x+y
else:
return rec(x-1,y)+rec(x,y-1)
print(rec(x,y))
public static void main(String[] args) throws Exception{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] s = br.readLine().split(" "); int x = Integer.parseInt(s[0]); int y = Integer.parseInt(s[1]); int[] dp=new int[y+1]; Arrays.fill(dp,1); for(int i=1;i<=x;i++) for(int j=1;j<=y;j++) dp[j]+=dp[j-1]; System.out.print(dp[y]); }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int m = scan.nextInt(), n = scan.nextInt(); //排列组合 m+n步选取m步 long a = 1, b = 1, c = 1; for (int i = 1; i <= m+n; i++) a *= i; for (int i = 1; i <= m; i++) b *= i; for (int i = 1; i <= n; i++) c *= i; System.out.println(a/(b*c)); } }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int x = sc.nextInt(); int y = sc.nextInt(); // 初始化边界 int[][] dp = new int[x + 1][y + 1]; for(int i = 0; i <= x; i++) dp[i][0] = 1; for(int i = 0; i <= y; i++) dp[0][i] = 1; // 动态规划 for(int i = 1; i <= x; i++){ for(int j = 1; j <= y; j++) dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; // 可能从上面,也可能从左边过来 } System.out.println(dp[x][y]); } }
#include <iostream> using namespace std; int main() { int nRows, nCols; while (cin >> nRows >> nCols) { if (nRows < 1 || nRows > 10 || nCols < 1 || nCols > 10) { cout << "0" << endl; continue; } int* pDP = new int[nRows + 1]; for (int i = 0; i <= nCols; ++i) pDP[i] = 1; for (int i = 1; i <= nRows; ++i) for (int j = 1; j <= nCols; ++j) pDP[j] = pDP[j - 1] + pDP[j]; cout << pDP[nCols] << endl; delete pDP; } }
递归即可解决该问题,好好的学习递归真的很有用,哈哈,共勉import java.util.Scanner; public class root { public static void main(String[] args){ Scanner input = new Scanner(System.in); while (input.hasNextInt()){ int disX = input.nextInt(); int disY = input.nextInt(); System.out.println(road(0,0, disX,disY)); } } public static int road(int x, int y, int disX, int disY){ int result = 0; if (x <= disX && y <= disY){ if (x == disX && y == disY){ return 1; }else { //向下走 result = result + road(x + 1, y, disX, disY); //向右走 result = result + road(x , y + 1, disX, disY); } return result; }else { return 0; } } }