输入两个整数
代表苹果数、盘子数。
输出一个整数,代表不同的分法数量。
3 2
2
在这个样例中,有
、
这两种不同的分法。
7 3
8
注意,由于苹果和盘子都是相同的,所以
和
是同一种分法。
思路有点抽象……
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int apples = in.nextInt(); int contains = in.nextInt(); System.out.println(getMethods(apples, contains)); } public static int getMethods(int apples, int contains) { // 苹果数量刚好每盘子一个或者只剩最后一个盘子,计一种方法 if (apples == 0 || contains == 1) { return 1; } if (apples < 0) { // 苹果数量不够每盘子一个 return 0; } // 每个盘子至少放了一个的情况和有若干个盘子没放的情况 return getMethods(apples-contains, contains) + getMethods(apples, contains-1); } }
package com.huawei.item.easy; import java.util.Scanner; public class SixtyOne { public static void main(String[] args) { //把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法? //注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。 Scanner in = new Scanner(System.in); int m = in.nextInt(); // m个苹果 int n = in.nextInt(); // n个盘子 int[][] dp = new int[m][n]; int sum = uniquePaths(m, n); System.out.println(sum); } private static int uniquePaths(int m, int n) { // dp[m][n] = dp[m][n-1]+dp[m-n][n] int[][] dp = new int[m + 1][n + 1]; // 初始化 for (int i = 0; i < m + 1; i++) { for (int j = 0; j < n + 1; j++) { // 初始化数据 if (i <= 1 || j <= 1) { dp[i][j] = 1; continue; } // 动态规划 if (i < j) { dp[i][j] = dp[i][j - 1]; } else { dp[i][j] = dp[i][j - 1] + dp[i - j][j]; } } } return dp[m][n]; } }
继续往下推导。
最后如果剩下1个苹果或者0个苹果,不管有多少盘子,无论是1个苹果1个盘子,还是1个苹果10个盘子,都只有一种放法
或者只剩下1个盘子,无论剩多少苹果,也都只有一种放法。
所以当 m <= 1 || n <= 1 时,初始化数值为1.
if (i <= 1 || j <= 1) { dp[i][j] = 1; continue; }
放苹果有两种情况:
当苹果数量<盘子数量时,不可能所有盘子都放苹果,只能去除一个盘子,向下计算。
if (i < j) { dp[i][j] = dp[i][j - 1];}
当苹果数量>=盘子数量时,上述两种情况都可以
例如:7个苹果放3个盘子 = 7个苹果放2个盘子 + 4个苹果放3个盘子里
else { dp[i][j] = dp[i][j - 1] + dp[i - j][j];}
//递归法 import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 注意 hasNext 和 hasNextLine 的区别 int a = in.nextInt(); int b = in.nextInt(); int count = count(a, b); System.out.println(count); } public static int count(int a, int b) { if(a ==0 || b ==1){ return 1; }else if(a < b){ return count(a,a); }else { return count(a,b-1)+count(a-b,b); } } }
import java.util.*; //由于本体苹果是相同的,盘子也是相同的 //所以每个盘子中的苹果只区分个数,每一个放的盘子也不能分先后; //所以我们在操作某一个盘子时只取i个苹果,但我们要保证我们分苹果的数量单调不减或者单调不增 //此处采用单调不增,即下一个盘子放的苹果数量<=当前放的苹果数量 //当前放的苹果数量不能低于剩余苹果数量平均放到剩余盘子中的数量,即(m-i)<=i*(n-1) //递归计算,除了携带m、n之外,还需传递当前可取最大苹果数max public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); while (in.hasNext()) { int m = in.nextInt(); int n = in.nextInt(); System.out.println(getAnswer(m, n,m)); } } public static int getAnswer(int m,int n,int max){//max用来限制当前盘子最大能取多少个苹果 if(n==1||m==0) {//定义只有一个盘子 或者只有0个苹果的分法 return 1; } int answersCount = 0; for (int i = 1; i <= Math.min(m,max); i++) { if((m-i)<=i*(n-1)){ answersCount+=getAnswer(m-i,n-1,i); } } return answersCount; } }
import java.util.Scanner; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException{ Scanner in = new Scanner(System.in); while (in.hasNextInt()) { int apple = in.nextInt(); int plate = in.nextInt(); int res = divide(apple,plate); System.out.println(res); } } //总共两大种情况 //1. apple数量大于plate数量,可以分为空盘子或不空盘子(即每个盘子至少放一个) //2. apple数量小于plate数量,此时,至少有plate-apple个空盘(对于计算放盘的数量而言,空盘无效),只当做apple = plate来计算(这样会把计算交给第一类) //结束条件:apple == 0(第一大类的不空盘子可能的结果(苹果数量<=盘子数量时的一种可能性));plate == 1(第一大类的不空盘子可能的结果/第一大类的空盘子可能的结果) public static int divide(int apple,int plate){ if(apple == 0 || plate == 1){ return 1; }else if(apple<plate){ return divide(apple,apple); }else{ return divide(apple-plate,plate) + divide(apple,plate - 1); } } }
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 苹果数 int m = in.nextInt(); // 果盘数 int n = in.nextInt(); System.out.println(dfs(m, n)); } /** * @param m 苹果 * @param n 盘子 * @return */ private static int dfs(int m, int n) { if (m == 0 || n == 1) { return 1; } if (n > m) { // 盘子比苹果多,肯定会空出盘子 return dfs(m, m); } return // 每个盘子都有苹果,相当于求解 m - n个苹果 放在盘子里(每个盘子都有一个苹果)有几种方法 dfs(m - n, n) + // 有空盘子 dfs(m, n - 1); } }
package huawei; /** * @author YXQ * @create 2022/8/27 17:28 */ import java.util.*; /** * 把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法? * 注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。 * 输入描述: * 输入两个int整数 * 输出描述: * 输出结果,int型 */ /** * 用递归能做 但是肯定不是最符合的做法 复杂度太高了 * * ********HashSet<List<Integer>> 能够查重排序后的(5,1,1),(1,5,1),(1, 1, 5)这种重复,只会出现一个。 */ public class HJ61 { static HashSet<List<Integer>> set=new HashSet<>(); public static void main(String[] args) { Scanner sc=new Scanner(System.in); int m=sc.nextInt(); int n=sc.nextInt(); //法1 // dfs(n,0,m,new ArrayList<Integer>()); // System.out.println(set.size()); //法2 // System.out.println(dfs(m,n)); //法3 System.out.println(putApple(m,n)); } /** * 动态规划方法 * dp[i][j]表示持有i个苹果,有j个盘子可以存放苹果,总共有 dp[i][j]种方法 * 初始情况:没有苹果,只有一种摆放方法。dp[0][j]=1 * 递推函数: * 1.当i-j<0即苹果数小于盘子数,因为多出来的j-i个盘子不会放苹则dp[i][j]=dp[i][i] * 2.当i>=j时:dp[i][j]=dp[i-j][j]+dp[i][j-1]下面的dfs解释了 * @param m * @param n * @return */ public static int putApple(int m,int n){ int[][] dp=new int[m+1][n+1]; for(int j=0;j<n+1;j++)dp[0][j]=1; for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ if(i-j<0){ dp[i][j]=dp[i][i]; }else{ dp[i][j]=dp[i-j][j]+dp[i][j-1]; } } } return dp[m][n]; } /** * 递归 * dfs(m,n)表示把m个苹果放在n个盘子中 分为两种情况 * 1.至少有一个盘子不放(确定有一个盘子不用)dfs(m,n-1) * 2.每个盘子都放苹果,此时从每一个盘子中取出一个苹果,不会影响放法的数量 dfs(m-n,n) * 则dfs(m,n)=dfs(m,n-1)+dfs(m-n,n); * 在情况1中 当n==1时(盘子为1时)只有一种放法(因为终止条件已经卡到n=1了,所以不用去考虑n=0的情况了) * 在情况2中 当m=0时 return 1(0个苹果时 每个盘子都不放 是一种放法) 当m<0时 return 0; * @param m * @param n * @return */ public static int dfs(int m,int n){ if(m==0||n==1)return 1; if(m<0)return 0; return dfs(m,n-1)+dfs(m-n,n); } /** * 方法1 递归 递归深度是盘子的数量 递归函数体是为每个盘子放一定数量的苹果 * 递归结束条件是 盘子完了&&苹果完了 * @param n * @param index * @param target * @param path */ public static void dfs(int n,int index,int target,List<Integer> path){ if(index==n){ if(target==0){ List<Integer> ans=new ArrayList<>(path); Collections.sort(ans); if(!set.contains(ans))set.add(ans); } return; } for(int i=0;i<=target;i++){ path.add(i); dfs(n,index+1,target-i,path); path.remove(path.size()-1); } } }
import java.util.Scanner; /** * 把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法? * 注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。 * * * 1、苹果数 < 盘子数,多余的盘子直接舍弃,因为多出来的盘子不可能放的了苹果。 * m < n : dp[m][n] = dp[m][m] * 2、苹果数 >= 盘子数,那么前面盘子都放苹果,‘放到第n个盘子时’,有两种选择 * 第n个盘子不放苹果,即舍弃第n个盘子:dp[m][n-1] * 第n个盘子放苹果,即到第n个盘子为止每个盘子都有苹果,所以只有m-n个苹果可以自由选择放哪些盘子里了:dp[m-n][n] * m >= n : dp[m][n] = dp[m-n][n] * 3、注意:其中苹果个数为0的dp[0][n]和盘子个数为1的dp[m][1]其放法默认初始化为1 */ public class HJ61_dp盘子放苹果 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int m = sc.nextInt(); int n = sc.nextInt(); int[][] dp = new int[m + 1][n + 1]; for (int i = 0; i <= m; i++) { dp[i][1]=1; } for (int i = 0; i <= n; i++) { dp[0][i]=1; } for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if(i<j) dp[i][j]=dp[i][i]; else dp[i][j] = dp[i][j - 1] + dp[i - j][j]; } } System.out.print(dp[m][n]); } }
import java.util.Scanner; public class Main { /** 1、苹果数 < 盘子数,多余的盘子直接舍弃,因为多出来的盘子不可能放的了苹果。 m < n : dp[m][n] = dp[m][m] 2、苹果数 >= 盘子数,那么前面盘子都放苹果,‘放到第n个盘子时’,有两种选择 第n个盘子不放苹果,即舍弃第n个盘子:dp[m][n-1] 第n个盘子放苹果,即到第n个盘子为止每个盘子都有苹果,所以只有m-n个苹果可以自由选择放哪些盘子里了:dp[m-n][n] m >= n : dp[m][n] = dp[m-n][n] 3、注意:其中苹果个数为0的dp[0][n]和盘子个数为1的dp[m][1]其放法默认初始化为1 */ public static void main(String[] args) { Scanner in = new Scanner(System.in); int m = in.nextInt(); int n = in.nextInt(); int[][] dp = new int[m+1][n+1]; for(int i=0;i<=m;i++){ for(int j=1;j<=n;j++){ if(i==0 || j==1) { dp[i][j] = 1; continue; } if(i<j) { dp[i][j] = dp[i][i]; } else { // 这里不会出现j-1=0的情况,上面当j=1的时候就已经跳过了 dp[i][j] = dp[i][j-1] + dp[i-j][j]; } } } System.out.print(dp[m][n]); } }
import java.util.Scanner; public class Main{ public static int ans(int m, int n){ if(n == 1 || m == 0)return 1; else if(m<n)return ans(m,m); else return ans(m, n-1) + ans(m-n, n); } public static void main(String[] args){ Scanner sc = new Scanner(System.in); int m = sc.nextInt(), n = sc.nextInt(); System.out.println(ans(m,n)); } }
我不懂怎么做,也不知道什么是动态规划,抄评论区动态规划,改了一下
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { int m = Integer.parseInt(sc.next()); int n = Integer.parseInt(sc.next()); System.out.println(fib(m, n)); } } static int fib(int m, int n) { int[][] dp = new int[m + 1][n + 1]; return dp(dp, m, n); } static int dp(int[][] dp, int m, int n) { if (m == 0 || n == 1) { return 1; } // 计算过不再计算 if (dp[m][n] != 0) { return dp[m][n]; } if (n > m) { dp[m][n] = dp(dp, m, n - 1); } else { dp[m][n] = dp(dp, m, n - 1) + dp(dp, m - n, n); } return dp[m][n]; } }
import java.util.*; public class Main { static int []a=new int[11]; static int count=0; static ArrayList<Integer> ans=new ArrayList<Integer>(); public static void dfs(int num,int n) { //num表示剩余的可以放置的苹果数 if(ans.size()==n+1 ) { if(num==0) count++; return; } for(int i=0;i<=num;i++) { if(i>=ans.get(ans.size()-1)) { ans.add(i); dfs(num-i,n); ans.remove(ans.size()-1); } } } public static void main(String[] args) { Scanner in=new Scanner(System.in); int m=in.nextInt(); int n=in.nextInt(); ans.add(0); dfs(m,n); System.out.println(count); } }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNextInt()){ int m = sc.nextInt(); int n = sc.nextInt(); System.out.println(calculate(m,n)); } } public static int calculate(int m,int n){ if(m < 0 || n <= 0){ return 0; } if(m == 1 || n == 1 || m == 0){ return 1; } return calculate(m,n-1)+calculate(m-n,n); } }
import java.util.Scanner; public class Main { /* 解析: 放苹果情况:(1)有空盘,(2)无空盘 有空盘理解为:f(m, n) = f(m, n-1),在n-1个盘上放苹果,一次类推直到n==1,只有1种放法 无空盘理解为:f(m, n) = f(m-n, n),在n个盘上放1个苹果,剩下的m-n苹果随意放,直到m<n时,返回0,当m=n,即m-n=0时,返回1 所以f(m, n) = f(m, n-1) + f(m-n, n); */ public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNextInt()) { System.out.println(countWays(sc.nextInt(), sc.nextInt())); } } // 动态规划 public static int countWays(int m, int n) { // 额外创建一行作为辅助行 int[][] dp = new int[m+1][n+1]; // 初始化(m-n=0时,1种摆法)(n=1, 1种摆法【可省略】) for (int j=0; j<n+1; j++) { dp[0][j] = 1; } // 遍历计算(f(m, n) = f(m, n-1) + f(m-n, n)) for (int i=1; i<m+1; i++) { for (int j=1; j<n+1; j++) { dp[i][j] = dp[i][j-1] + (i < j ? 0 : dp[i-j][j]); } } return dp[m][n]; } }