有一个X*Y的网格,小团要在此网格上从左上角到右下角,只能走格点且只能向右或向下走。请设计一个算法,计算小团有多少种走法。给定两个正整数int x,int y,请返回小团的走法数目。
题意不太明确,注意只能走格点,你画个网格就知道了。
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int m = sc.nextInt(); int[][] dp = new int[n + 1][m + 1]; for(int i = 0; i <= n; i ++) { for(int j = 0; j <= m; j ++) { if(i == 0 || j == 0) { dp[i][j] = 1; } else { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } } System.out.println(dp[n][m]); } }
或者直接计算 C(n + m, n)
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int m = sc.nextInt(); int res = 1; for(int i = 1; i <= n; i ++) { res = res * (m + i) / i; } System.out.println(res); } }
因为只能向右走和向下,所以无论怎么走,向右的总距离和向下总距离都只能是x和y(即网格大小,曼哈顿距离不变),可以转换成排列组合问题,假设用0代表向右,1代表向左,题目转化成用x个0和Y个1能组成多少个不同的数,由排列组合公式可知,组合数应当是:
def cal_couple(num,i): sum = 1 dvi_sum = 1 for i in range(i): sum = sum*(num-i) dvi_sum = dvi_sum * (i+1) return (sum/dvi_sum) if __name__ == '__main__': x,y = list(map(int,input().split())) print('%d' %(cal_couple(x+y,x)))PS:python学得不好,见谅
就是一个排列组个问题 一共要走步,哪步向右下走
注意阶乘溢出就行
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Solution15_方格走法 {
public static void main(String[] args) throws IOException { BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); String[] split = bf.readLine().split(" "); int x = Integer.parseInt(split[0]); int y = Integer.parseInt(split[1]); long a = 1,b = 1; int sum = x + y; int min = Math.min(x,y); for (int i = 1; i <= min; i++) { a *= i; b *= sum; sum--; } System.out.println(b / a); }
}
import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int x = scanner.nextInt(); int y = scanner.nextInt(); int a = x + y; int b = (x <= y) ? x : y; long denominator = 1, numerator = 1; for (int i = 1; i <= b; i++, a--) { denominator *= i; // 1*2*3... numerator *= a; // 10*9*8... } // (10*9*8*...)/(1*2*3*...) System.out.println(numerator / denominator); } }
public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int x = in.nextInt(); int y = in.nextInt(); getKind(x,y,0,0); System.out.println(count); } private static int count = 0; private static void getKind(int rows,int cols,int r,int c){ if (r == rows && c == cols){ count++; return; } //向下走 if (r+1<=rows) getKind(rows,cols,r+1,c); //向右走 if (c+1<=cols) getKind(rows,cols,r,c+1); } }
#include <iostream> #include <vector> using namespace std; // DP 做法 int main(const int argc, const char** argv) { int m, n; cin >> m >> n; vector<vector<int>> grid(m + 1, vector<int>(n + 1, 1)); for (int y = 1; y <= m; ++y) for (int x = 1; x <= n; ++x) grid[y][x] = grid[y - 1][x] + grid[y][x - 1]; cout << grid[m][n]; return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> int depth_first_search_with_memorization_algorithm(int* dp, const int m, const int n, int x, int y) { if (x == n || y == m) return 0; // out of the boundary if (dp[y * n + x] >= 0) return dp[y * n + x]; // 防止重复求解子问题 if (x == n - 1 && y == m - 1) return dp[y * n + x] = 1; // reach to the goal int count = 0; count += depth_first_search_with_memorization_algorithm(dp, m, n, x + 1, y); // right count += depth_first_search_with_memorization_algorithm(dp, m, n, x, y + 1); // down return dp[y * n + x] = count; } int main(const int argc, const char** const argv) { int m, n; fscanf(stdin, "%d %d", &m, &n); ++m, ++n; int dp[m][n]; memset(dp, -1, sizeof dp); fprintf(stdout, "%d\n", depth_first_search_with_memorization_algorithm(dp, m, n, 0, 0)); return 0; }
/* 动态规划:dp[i][j]表示位于网格行列为i,j的时候所有的走法数目 dp[i][j] = dp[i][j-1] + dp[i-1][j] 当只有一行n列时只有一种走法,只有n行一列时只有一种走法 */ import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner input = new Scanner(System.in); int x = input.nextInt(); int y = input.nextInt(); int[][] dp = new int[x+1][y+1]; //动态规划 for(int i = 0;i<x+1;i++){ for(int j = 0;j<y+1;j++){ if(i==0||j==0){ dp[i][j]=1; }else{ dp[i][j]=dp[i][j-1]+dp[i-1][j]; } } } //结果 System.out.println(dp[x][y]); } }
import java.util.Scanner; public class Main { static int count =0; static int x; static int y; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); x=scanner.nextInt(); y=scanner.nextInt(); dfs(0,0); System.out.println(count); } private static void dfs(int currentX,int currentY){ if (currentX>x||currentY>y) return; if (currentX==x&¤tY==y){ count++; return; }else { dfs(currentX+1,currentY); dfs(currentX,currentY+1); } } }
static int x; static int y; static int[][] arr; static int dfs(int currentX,int currentY){ if (currentX>x||currentY>y) return 0; else if (currentX==x&¤tY==y) return 1; else if (arr[currentX][currentY]!=0) return arr[currentX][currentY]; else { arr [currentX][currentY]= dfs(currentX+1,currentY)+ dfs(currentX,currentY+1); return arr[currentX][currentY]; } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); x=scanner.nextInt(); y=scanner.nextInt(); arr =new int[x+1][y+1]; System.out.println(dfs(0,0)); }
/* 利用递归来解决这个问题 我们从最终点出发往前递推x-1或者y-1 当有一个坐标变成0后说明有了一条道 而均不为0时继续-1的操作 */ #include <stdio.h> int x,y,count=0; void way(int n,int m){ if(n*m == 0){ count ++; return; } way(n-1,m); way(n,m-1); } int main(){ scanf("%d %d", &x, &y); way(x,y); printf("%d",count); return 0; }
#include<bits/stdc++.h> using namespace std; int main() { int m, n; cin >> m >> n; // 0,0 -> m, n vector<vector<int>> f(m+1, vector<int>(n+1,0)); f[0][0] = 1; for (int i=0; i<=m; ++i) { for (int j=0; j<=n; ++j) { if (i-1 >= 0) { f[i][j] += f[i-1][j]; } if (j-1 >= 0) { f[i][j] += f[i][j-1]; } } } cout << f[m][n] << endl; return 0; }
本题是很直观的动态规划题目,构造一个二维数组对应我们坐标右下方正增长的网格。 以f(x,y)为到(x,y)点的方法数,则f(x,y)=f(x-1,y)+f(x,y-1) x>1,y>1 f(x,y)=f(x-1,y) x>1,y==0 f(x,y)=f(x,y-1) x==0,y>1 初始值f(1,0)=1. f(0,1)=1 #include<iostream> #include<vector> using namespace std; //动态规划 int main() { int x,y; cin>>x>>y; //这里是因为如果我们的网格是x行y列,那么我们的对应的网点数为x+1行y+1列。 x++; y++; vector<vector<int> > tmp(x); for(int i=0;i<x;i++) { for(int j=0;j<y;j++) { tmp[i].push_back(0); } } //初始值 tmp[1][0]=1; tmp[0][1]=1; for(int i=0;i<x;i++) { for(int j=0;j<y;j++) { if(i==0&&j>1) { tmp[i][j]=tmp[i][j-1]; } if(i>1&&j==0) { tmp[i][j]=tmp[i-1][j]; } if(i>=1&&j>=1) { tmp[i][j]=tmp[i-1][j]+tmp[i][j-1]; } } } //最后输出整个网点数组的右下角值即可 cout<<tmp[x-1][y-1]; }
"""" 考虑动态规划 设dp[x][y]为x*y的网格,每次只能向两个方向,有以下规律: dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 边界条件为 dp[i][j]=1,(当i=0或j=0) """ if __name__ == "__main__": x, y = map(int, input().strip().split()) dp = [[1] * (y + 1) for _ in range(x + 1)] for i in range(1, x + 1): for j in range(1, y + 1): dp[i][j] = dp[i - 1][j] + dp[i][j - 1] print(dp[x][y])
#include <bits/stdc++.h>using namespace std;int main(){int x, y;int dp[11][11] = {0};for(int i=0;i<=10;i++){for(int j=0;j<=10;j++){if(i==0 && j==0)dp[i][j] = 1;else if(i==0)dp[i][j] = dp[i][j-1];else if(j==0)dp[i][j] = dp[i-1][j];elsedp[i][j] = dp[i-1][j] + dp[i][j-1];}}// for(int i=1;i<=10;i++)// for(int j=1;j<=10;j++)// {// if(j==10)// cout<<dp[i][j]<<endl;// else// cout<<dp[i][j]<<" ";// }while(cin>>x>>y){cout<<dp[x][y]<<endl;}return 0;}
package main import ( "fmt" ) func main() { var x,y int fmt.Scan(&x,&y) mat:=make([][]int,x+1) for i,_:=range mat{ mat[i]=make([]int,y+1) } for i:=0;i<=y;i++{ mat[0][i]=1 } for i:=0;i<=x;i++{ mat[i][0]=1 } for i:=1;i<=x;i++{ for j:=1;j<=y;j++{ mat[i][j]=mat[i-1][j]+mat[i][j-1] } } // fmt.Printf("%v\n",mat) fmt.Print(mat[x][y]) }
#include <iostream> #include <vector> using namespace std; int main() { int x = 0, y = 0; cin >> x >> y; vector<vector<int>> vec0; //坑点:路径为网格点而不是网格,所以要加1 vector<int> vec1(y+1, 0); for (int i = 0; i <= x; i++) { vec0.push_back(vec1); } for (int i = 0; i <= x; i++) { vec0[i][0] = 1; } for (int j = 0; j <= y; j++) { vec0[0][j] = 1; } for (int i = 1; i <= x; i++) { for (int j = 1; j <= y; j++) { vec0[i][j] = vec0[i - 1][j] + vec0[i][j - 1]; } } cout << vec0[x][y] << endl; return 0; }
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[][] dp = new int[x+1][y+1]; dp[0][0] = 0; for(int i = 1;i < x+1;i++){ dp[i][0] = 1; } for(int j = 1;j < y+1;j++){ dp[0][j] = 1; } for(int i = 1;i < x+1;i++){ for(int j = 1;j < y+1;j++){ dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } System.out.println(dp[x][y]); } }
#include<iostream> #include<vector> using namespace std; int main() { int x,y; cin>>x>>y; int(*p)[11]=new int[x+1][11]; // vector<vector<int>> v(x+1); // for(int i=0;i<v.size();i++) // v[i].resize(y+1); for(int i=0;i<y+1;i++) p[0][i]=1; for(int i=0;i<x+1;i++) p[i][0]=1; for(int i=1;i<x+1;i++) { for(int j=1;j<y+1;j++) { p[i][j]=p[i-1][j]+p[i][j-1]; } } cout<<p[x][y]; }