(1)P1255 数楼梯
很经典的一道入门递归题。递推公式为f(n)=f(n-1)+f(n-2)。这里数据量很大,要用大数进行递归
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
BigInteger b=new BigInteger("1");
BigInteger a=new BigInteger("2");
BigInteger bi;
for(int i=3;i<=n;i++) {
bi=new BigInteger(a.add(b).toString());
b=a;
a=bi;
}
if(n==0) {
System.out.println(0);
}
else if(n==1) {
System.out.println(b);
}
else {
System.out.println(a);
}
}
}
(2)P1002 过河卒
一开始肯定以为是用dfs做,因为搜索路径的题目很多都是用dfs做的。然而这道题实际是用动态规划。转移方程不难推出是dp[i][j]=dp[i-1][[j]+dp[i][j-1]。dp代表的是到达该点的路径数目,因为它可能从上面和左边过来,所以有了这个状态转移方程。
dfs做法:
import java.util.Scanner;
public class Main {
static int[] dx= {0,-2,-1,1,2,-2,-1,1,2};
static int[] dy= {0,-1,-2,-2,-1,1,2,2,1};
static int n,m,x2,y2,sum=0;
static boolean[][] vis;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();m=sc.nextInt();x2=sc.nextInt();y2=sc.nextInt();
vis=new boolean[n+1][m+1];
// vis[0][0]=true;
dfs(0,0);
System.out.println(sum);
}
public static void dfs(int x,int y) {
if(x==n&&y==m) {
sum++;
return;
}
vis[x][y]=true;
if(x+1<=n&&!vis[x+1][y]&&judge(x+1,y)) {
vis[x+1][y]=true;
dfs(x+1,y);
vis[x+1][y]=false;
}
if(y+1<=m&&!vis[x][y+1]&&judge(x,y+1)) {
vis[x][y+1]=true;
dfs(x,y+1);
vis[x][y+1]=false;
}
}
public static boolean judge(int x,int y) {
for(int i=0;i<9;i++) {
int tx=x2+dx[i];
int ty=y2+dy[i];
if(tx==x&&ty==y)return false;
}
return true;
}
}
dp做法:
import java.util.Scanner;
public class Main {
static int[] dx= {0,-2,-1,1,2,-2,-1,1,2};
static int[] dy= {0,-1,-2,-2,-1,1,2,2,1};
static int n,m,x2,y2;
static boolean[][] vis;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();m=sc.nextInt();x2=sc.nextInt();y2=sc.nextInt();
long[][] dp=new long[n+1][m+1];
dp[0][0]=1;
for(int i=0;i<=n;i++) {
for(int j=0;j<=m;j++) {
if(i==0&&j==0) {
continue;
}
if(judge(i-1,j)&&judge(i,j-1))dp[i][j]=dp[i-1][j]+dp[i][j-1];
else if(!judge(i-1,j)&&judge(i,j-1))dp[i][j]=dp[i][j-1];
else if(judge(i-1,j)&&!judge(i,j-1))dp[i][j]=dp[i-1][j];
else dp[i][j]=0;
}
}
System.out.println(dp[n][m]);
}
public static boolean judge(int x,int y) {
for(int i=0;i<9;i++) {
int tx=x2+dx[i];
int ty=y2+dy[i];
if(tx==x&&ty==y)return false;
}
return 0<=x&&x<=n&&0<=y&&y<=m;
}
}
(3)P1044 栈
和上题一样,可以用dfs来做,用Java自带的栈数据结构来模拟出入栈的情况。如果所有元素都出栈,计数加1,代表这种情况已经统计了。
import java.util.Scanner;
import java.util.Stack;
public class Main {
static Stack<Integer> s=new Stack<Integer>();
static int n,all=0;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
dfs(0,0,n);
System.out.println(all);
}
//sum代表栈里的元素个数,go代表出栈的元素个数,now代表还未入栈的元素个数
public static void dfs(int sum,int go,int now) {
if(go==n) {
all++;
return;
}
if(now>0) {
s.push(1);
dfs(sum+1,go,now-1);
s.pop();
}
if(sum>0) {
s.pop();
dfs(sum-1,go+1,now);
s.push(1);
}
}
}
但这种情况因为太多重复的递归会导致过不了所有测试点,所以这里可以改成记忆化递归。
import java.util.Scanner;
import java.util.Stack;
public class Main {
static Stack<Integer> s=new Stack<Integer>();
static int n;
static int[][] f;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
f=new int[n+1][n+1];
System.out.println(dfs(0,0,n));
}
//sum代表栈里的元素个数,go代表出栈的元素个数,now代表还未入栈的元素个数
public static int dfs(int sum,int go,int now) {
if(go==n) {
return 1;
}
if(f[sum][now]!=0) {
return f[sum][now];
}
if(now==0) {
f[sum][now]=dfs(sum-1,go+1,now);
}
else if(sum==0) {
f[sum][now]=dfs(sum+1,go,now-1);
}
else {
f[sum][now]=dfs(sum+1,go,now-1)+dfs(sum-1,go+1,now);
}
return f[sum][now];
}
}
当然这题也可以用动态规划来做,当当 i个数进栈,j−1 个数出栈的时候,只要再出一个数,便是i个数进栈,jj个数出栈的情况,同理,对于进栈 i−1 个数,出栈 j个数,在进栈一个数便是f[i,j]f[i,j]了,于是就有了递归式:f[i,j]=f[i-1,j+1]f[i,j]=f[i−1,j+1].代码就不再给出了。
(4)P1028 数的计算
又是一道递归题目,同样也是用记忆化递归进行优化,因为左边的数不能超过自身的一半,而且自身也算一种情况。我们就设置一个变量sum=1,再去递归的加上左边数字的情况。
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
System.out.println(dfs(n));
}
static int[] arr=new int[1010];
public static int dfs(int n) {
if(arr[n]!=0)
return arr[n];
int sum=0;
sum++;
for(int i=n/2;i>0;i--) {
sum+=dfs(i);
}
return arr[n]=sum;
}
}
(5)P1464 Function
按照题目要求写一个函数,题目已经提示的非常明显了。递归的层数会非常多,肯定要我们加个记忆化递归呀。当然,不用开题目给出的那么大数字的数组,肯定开不下,当abc有一个超过20的时候,就直接当作20处理,所有开20大小的三维数组即可。
import java.util.Scanner;
public class Main {
static long[][][] f=new long[30][30][30];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(true) {
Long a=sc.nextLong(),b=sc.nextLong(),c=sc.nextLong();
if(a==-1&&b==-1&&c==-1) {
return;
}
System.out.println("w("+a+", "+b+", "+c+") = "+w(a,b,c));
}
}
public static long w(long a,long b,long c) {
if(a<=0||b<=0||c<=0)
return 1;
else if(a>20||b>20||c>20)
return w(20,20,20);
else if(f[(int) a][(int) b][(int) c]!=0)
return f[(int) a][(int) b][(int) c];
else if(a<b&&b<c) {
f[(int) a][(int) b][(int) c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
return f[(int) a][(int) b][(int) c];
}
else
{
f[(int) a][(int) b][(int) c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
return f[(int) a][(int) b][(int) c];}
}
}
(6)
(7)P2437 蜜蜂路线
很明显的斐波拉契数列嘛。只不过现在不是从1开始。而从m开始,那我们把m当作1来处理是一样的。这里要用记忆化递归和大数。
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static BigInteger[] arr=new BigInteger[1010];
static int m;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
m=sc.nextInt();
int n=sc.nextInt();
for(int i=0;i<arr.length;i++) {
arr[i]=BigInteger.valueOf(0);
}
System.out.println(f(n));
}
public static BigInteger f(int n) {
if(n==m) {
return BigInteger.valueOf(1);
}
if(n==m+1)
return BigInteger.valueOf(1);
if(!arr[n].equals(BigInteger.valueOf(0))) {
return arr[n];
}
arr[n]=f(n-1).add(f(n-2));
return arr[n];
}
}
(8)P1164 小A点菜 (9)P1036 选数 (10)-(12)待更新 (13)P1010 幂次方 (14)P1228 地毯填补问题
很明显的一道01背包问题,不过这里并不是求最大价值,而是求刚好装满的情况。所以这里dp[i][j]应该表示的是前i件物品在有j元的情况下能刚好花完的方案数目。状态转移方程有三种情况:当a[i]>j时,即钱不够买这个物品时,dp[i][j]=dp[[i-1][j],很好理解就是说有这件物品和没有这件物品都是一样的,因为买不了。第二种情况,当a[i]=j时,dp[i][j]=dp[i-1][j]+1,刚好能买就是一种情况,所以在之前的方案数加1,第三种情况,当a[i]import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt();
int[][] dp=new int[n+1][m+1];
int[] arr=new int[n+1];
for(int i=1;i<=n;i++) {
arr[i]=sc.nextInt();
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(arr[i]>j) {
dp[i][j]=dp[i-1][j];
}
else if (arr[i]==j){
dp[i][j]=dp[i-1][j]+1;
}
else {
dp[i][j]=dp[i-1][j]+dp[i-1][j-arr[i]];
}
}
}
System.out.println(dp[n][m]);
}
}
在暴力枚举那个题单中出现过的题目,就是一个搜索,推出所有的情况,然后判断是否为素数。import java.util.Scanner;
public class Main {
static int n,k;
static int[] arr;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
k=sc.nextInt();
arr=new int[n];
for(int i=0;i<n;i++) {
arr[i]=sc.nextInt();
}
dfs(0,0,0);
System.out.println(count);
}
static int count=0;
public static void dfs(int i,int kk,int sum) {
if(kk==k) {
if(isP(sum)) {
count++;
}
return;
}
if(i==n) {
return;
}
dfs(i+1,kk+1,sum+arr[i]);//选
dfs(i+1,kk,sum); //不选
}
public static boolean isP(int n) {
for(int i=2;i*i<=n;i++) {
if(n%i==0) {
return false;
}
}
return true;
}
}
这题在蓝桥杯练习系统中出现过 解析链接import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
f(n);
}
public static void f(int n) {
if(n==0) { //这3个if都是终止条件
System.out.print("0");
return;
}
if(n==1) {
System.out.print("2(0)");
return;
}
if(n==2) {
System.out.print("2");
return;
}
System.out.print(2); //如果在上面if没有被终止,那么肯定n>2的,那么肯定要进行递归,所以这里先写个2
int sum=1,pow=0;//sum最接近n的2的幂次方数,pow代表的幂方
while(sum<=n) {
pow++;
sum*=2;
}
sum/=2; //这里肯定是多算了一次,因为sum要大于n才停止循环
pow--;
if(pow==0||pow==2) { //如果这个幂是0或者2可以直接出答案,如果是1则不用处理
System.out.print("("+pow+")");
}
if(pow>=3) { //如果大于3的话,肯定还要分解
System.out.print("(");
f(pow);
System.out.print(")");
}
n-=sum; //把n减掉最接近n的2的幂次方这个数
if(n!=0) { //如果剩下的数不为0就要继续递归,并添置+号
System.out.print("+");
f(n);
}
}
}
这道题以前是道省选题,不知为啥变成普及-了,明显这题难度不止普及-。这道题主要思路是分治,因为对于一个22的正方形而言,只要我们给一个特殊点,那么形状就是固定的了。而44可以看作4个22,我们个4个22的砖块交界处铺上一块地毯,那么每块地毯上都有一个特殊点。import java.io.PrintWriter;
import java.util.Scanner;
public class Main{
static PrintWriter out;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
out=new PrintWriter(System.out);
int k=sc.nextInt(),x=sc.nextInt(),y=sc.nextInt(),n=1;
for(int i=1;i<=k;i++) {
n*=2;
}
dfs(1,1,n,n,x,y);
out.close();
}
public static void dfs(int x1,int y1,int x2,int y2,int x,int y) {
if(x2-x1==1&&y2-y1==1) {
if (x==x1&&y==y1)System.out.printf("%d %d 1\n",x2,y2);
if (x==x1&&y==y2) System.out.printf("%d %d 2\n",x2,y1);
if (x==x2&&y==y1) System.out.printf("%d %d 3\n",x1,y2);
if (x==x2&&y==y2) System.out.printf("%d %d 4\n",x1,y1);
return;
}
int xx=(x2+x1)/2,yy=(y2+y1)/2;
if(x<=xx&&y<=yy) {
dfs(x1,y1,xx,yy,x,y);
out.printf("%d %d 1\n",xx+1,yy+1);
dfs(xx+1,y1,x2,yy,xx+1,yy);
dfs(xx+1,yy+1,x2,y2,xx+1,yy+1);
dfs(x1,yy+1,xx,y2,xx,yy+1);
}
else if (x<=xx&&y>yy)
{
dfs(x1,yy+1,xx,y2,x,y);
out.printf("%d %d 2\n",xx+1,yy);
dfs(x1,y1,xx,yy,xx,yy);
dfs(xx+1,y1,x2,yy,xx+1,yy);
dfs(xx+1,yy+1,x2,y2,xx+1,yy+1);
}
else if (x>xx&&y<=yy)
{
dfs(xx+1,y1,x2,yy,x,y);
System.out.printf("%d %d 3\n",xx,yy+1);
dfs(xx+1,yy+1,x2,y2,xx+1,yy+1);
dfs(x1,y1,xx,yy,xx,yy);
dfs(x1,yy+1,xx,y2,xx,yy+1);
}
else if (x>xx&&y>yy)
{
dfs(xx+1,yy+1,x2,y2,x,y);
System.out.printf("%d %d 4\n",xx,yy);
dfs(x1,y1,xx,yy,xx,yy);
dfs(x1,yy+1,xx,y2,xx,yy+1);
dfs(xx+1,y1,x2,yy,xx+1,yy);
}
}
}