一 袋鼠过河
题目描述:
一只袋鼠要从河这边跳到河对岸,河很宽,但是河中间打了很多桩子,每隔一米就有一个,每个桩子上都有一个弹簧,袋鼠跳到弹簧上就可以跳的更远。每个弹簧力量不同,用一个数字代表它的力量,如果弹簧力量为5,就代表袋鼠下一跳最多能够跳5米,如果为0,就会陷进去无法继续跳跃。河流一共N米宽,袋鼠初始位置就在第一个弹簧上面,要跳到最后一个弹簧之后就算过河了,给定每个弹簧的力量,求袋鼠最少需要多少跳能够到达对岸。如果无法到达输出-1
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] num=new int[n];
for(int i=0;i<n;i++)
num[i]=sc.nextInt();
int[] jump=new int[n+1];
for(int m=1;m<n+1;m++)
jump[m]=10000;
jump[0]=1;
for(int k=1;k<=n;k++){
//每次 看走到第k个地方的时候,走了多少步
//走的步数与上一步的走法有关
for(int j=k-1;j>=0;j--){
if(num[j]==0)
continue;
if(j+num[j]>=k)//从j的位置到k的位置是可达的,即一步能跳到
jump[k]=Math.min(jump[k],jump[j]+1);//则到位置k的步数取当前最小值
}
}
if(jump[n]==10000)
System.out.println(-1);
else
System.out.println(jump[n]-1);
}
}
题目二:跳石板
题目描述:
小易来到了一条石板路前,每块石板上从1挨着编号为:1、2、3.......
这条石板路要根据特殊的规则才能前进:对于小易当前所在的编号为K的 石板,小易单次只能往前跳K的一个约数(不含1和K)步,即跳到K+X(X为K的一个非1和本身的约数)的位置。 小易当前处在编号为N的石板,他想跳到编号恰好为M的石板去,小易想知道最少需要跳跃几次可以到达。
例如:
N = 4,M = 24:
4->6->8->12->18->24
于是小易最少需要跳跃5次,就可以从4号石板跳到24号石板
/*动态规划的思想 状态转移方程为:steps[i+j] = min(steps[i]+1,steps[i+j]) //i为石板编号,j为i的约数 steps[N] = 0 */
import java.util.Scanner;
import java.util.ArrayList;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();
//维护一个整型数组,存放从初始位置到到每一个位置的所需要走的最少步骤
//注意这里数组下标从0到n-1里面存的都是没有用的
//除了下标为n的位置赋值为0 其余都赋值为最大值
int[] step=new int[m+1];
for(int k=n+1;k<m+1;k++){
step[k]=Integer.MAX_VALUE;
}
//这样写会超时 换一种思路:不是每次遍历之前的每一个位置然后判断其是否满足条件
//而是直接看当前位置能到达的所有位置,即当前位置的所有约数+i
//相较于之前的思路 是一种从前到后的想法 之前是每一个位置 从后往前看
/* for(int i=n+2;i<=m;i++){
//到每一个位置上的最少步数都与之前的走法有关
for(int j=i-2;j>=n;j--){
if(step[j]==Integer.MAX_VALUE)
continue;
if(j%(i-j)==0 && i-j!=j){
//可达且约数不是本身也不是1,则最少步数取当前最短和上一步最短+1中的最小值
step[i]=Math.min(step[i],step[j]+1);
}
}
}
*/
//新思路实现:
for(int i=n;i<=m-2;i++){
//如果当前位置本身就不可达 则跳过
//注意:这个方法是在这里判断的 因为当前位置已经在遍历之前位置的时候更新过了 如果还是最大值 则说明不可达
//之前方法是从后往前更新的 所以不能上来就判断
if(step[i]==Integer.MAX_VALUE)
continue;
ArrayList<Integer> factors=getFactors(i);//存放当前位置的所有约数
//遍历所有约数
for(int j=0;j<factors.size();j++){
int temp=i+factors.get(j);
if(temp<=m){
step[temp]=Math.min(step[temp],step[i]+1);
}
}
}
if(step[m]==Integer.MAX_VALUE){
System.out.println(-1);
}else{
System.out.println(step[m]);
}
}
//求除了本身和1之外的所有约数的函数
public static ArrayList<Integer> getFactors(int n){
ArrayList<Integer> res=new ArrayList<Integer>();
//int bound=Math.sqrt(n);
for(int i=2;i*i<=n;i++){
if(n%i==0){
res.add(i);
if(i!=n/i)
res.add(n/i);
}
}
return res;
}
}
题目三:网格的走法
题目描述:有一个X*Y的网格,小团要在此网格上从左上角到右下角,只能走格点且只能向右或向下走。请设计一个算法,计算小团有多少种走法。给定两个正整数int x,int y,请返回小团的走法数目。
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
//String s=sc.next();
//String[] str=s.split(",");
//int x=Integer.parseInt(str[0]);
//int y=Integer.parseInt(str[1]);
//原来是动态规划。。。。不是深度优先搜索
int x=sc.nextInt();
int y=sc.nextInt();
int[][]step=new int[11][11];
int i=0;
int j=0;
for(i=1;i<=x;i++)
step[i][0]=1;
for(j=1;j<=y;j++)
step[0][j]=1;
i=1;
j=1;
for(int m=1;m<=x;m++){
for(int n=1;n<=y;n++)
step[m][n]=step[m-1][n]+step[m][n-1];
}
System.out.println(step[x][y]);
}
}
题目四:数字和为sum的方法数
题目描述:
给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。
当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int sum=sc.nextInt();
int[] num=new int[n+1];
for(int k=1;k<=n;k++)
num[k]=sc.nextInt();
System.out.println(dp(n,sum,num));
}
public static long dp(int n,int sum,int[] num){
//利用动态规划的思想
//二维数组dp dp[i][j]表示前i个元素构成和为j的方案数
long[][] dp=new long[n+1][sum+1];
//初始化dp
//前i个元素构成和为0的方案数为1,即啥也不取
for(int i=0;i<=n;i++){
dp[i][0]=1;
}
//前0个元素构成和为任意值的方案数为0 即dp[0][0...n-1]为0,取默认值
for(int i=1;i<=sum;i++)
dp[0][i]=0;
//正式开始dp啦
for(int i=1;i<=n;i++){
for(int j=1;j<=sum;j++){
//递推公式:
//如果第i个元素小于等于j,则分为取第i个元素和不取两种选择
//此时前i个元素构成和为j的方案数 为前i-1个元素构成和为j(不取第i个元素)的方案数+前i-1个元素构成和为j-num[i]的方案数
//如果第i个元素大于j 则只有一种情况了 就是不取第i个元素
if(num[i]<=j)
dp[i][j]=dp[i-1][j]+dp[i-1][j-num[i]];
else
dp[i][j]=dp[i-1][j];
}
}
return dp[n][sum];
}
}
注意dp要声明为long型因为会溢出,另外num的下标和dp的下标要对应上 注意这里num是从下标1开始赋值的 一直赋值到下标为n;