有一个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];
}