Java 递归、DFS、剪枝、回溯例题
上楼梯
有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶、3阶。 请实现一个方法,计算小孩有多少种上楼的方式。
给定一个正整数int n,请返回一个数,代表上楼的方式数。
保证n小于等于100000。
【代码】
public static int n;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
System.out.println(fun(0));
}
// 1 2 3
public static int fun(int sum) {
if (n == sum) {
return 1;
}
if (sum > n) {
return 0;
}
return fun(sum + 1) + fun(sum + 2) + fun(sum + 3);
}
机器人走方格
有一个XxY的网格,一个机器人只能走格点且只能向右或向下走,要从左上角走到右下角。 请设计一个算法,计算机器人有多少种走法。
给定两个正整数int x,int y,请返回机器人的走法数目。
保证x+y小于等于12。
【代码】
public static int ans;
public static int x,y;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
x = scan.nextInt();
y = scan.nextInt();
f(1,1);
System.out.println(ans);
}
public static void f(int i,int j) {
if(i==x&&j==y) {
ans++;
return;
}
if(i==x+1||j==y+1) {
return;
}
f(i+1,j); // 往下走
f(i,j+1); // 往右走
}
硬币表示
假设我们有8种不同面值的硬币{1,2,5,10,20,50,100,200},用这些硬币组合够成一个给定的数值n。 例如n=200,那么一种可能的组合方式为 200 = 3 1 + 1*2 + 1*5 + 2*20 + 1 50 + 1 * 100. 问总共有多少种可能的组合方式?
static int money[] = { 1, 2, 5, 10, 20, 50, 100, 200 };
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
System.out.println(combine(n, 7));
}
public static int combine(int n, int k) {
if (n < 0) {
return 0;
}
if (n == 0) {
return 1;
}
int cut = 0;
for (int i = 0; k >= 0 && i * money[k] <= n; i++) {
cut = cut + combine(n - i * money[k], k - 1);
}
return cut;
}
剪格子 dfs剪枝回溯
【问题描述】
如图p1.jpg所示,3 x 3 的格子中填写了一些整数。
我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是60。
本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等。
如果存在多种解答,请输出包含左上角格子的那个区域包含的格子的最小数目。
如果无法分割,则输出 0
程序输入输出格式要求:
程序先读入两个整数 m n 用空格分割 (m,n<10)
表示表格的宽度和高度
接下来是n行,每行m个正整数,用空格分开。每个整数不大于10000
程序输出:在所有解中,包含左上角的分割区可能包含的最小的格子数目。
例如:
用户输入:
3 3
10 1 52
20 30 1
1 2 3
则程序输出:
3
再例如:
用户输入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100
则程序输出:
10
(参见p2.jpg)
资源约定:
峰值内存消耗(含虚拟机) < 64M
CPU消耗 < 5000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.6及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
【代码】
public static int[][] g,vis;
private static int n, m,total;
private static int ans = Integer.MAX_VALUE;
static void dfs(int i, int j, int steps, int sum) {
if (i < 0 || i == n || j < 0 || j == m||vis[i][j]==1) {
return;
}
if(sum==total/2) {
ans = Math.min(ans,steps-1);
return;
}if(sum>total/2) {
return;
}
vis[i][j] = 1;
dfs(i - 1, j, steps + 1, sum + g[i][j]); // down
dfs(i + 1, j, steps + 1, sum + g[i][j]); // up
dfs(i, j - 1, steps + 1, sum + g[i][j]); // left
dfs(i, j + 1, steps + 1, sum + g[i][j]); // left
vis[i][j] = 0;
}
public static void main(String[] args) {
// 试探 —— 解的搜索 1、深搜2、宽搜3、二分搜索
// dfs 剪枝 回溯
Scanner scan = new Scanner(System.in);
m = scan.nextInt();
n = scan.nextInt();
g = new int[n][m];
vis = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
g[i][j] = scan.nextInt();
total = total + g[i][j];
}
}
// =完成输入=
dfs(0, 0, 0, 0);
System.out.println(ans);
}