动态规划入门之二维数组的动态规划(过河卒)

P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

过河卒,首先科普一下象棋里面的马的跳跃一步的规则吧(这题真够坑人的,连个规则都不给出,害得我第一次交就全wa)。一张图解释

 

大家看所有标记为p的点的坐标就是马跳一步和原来的位置。解决这个问题之后,我们大家来想怎么做,从起点怎么到达终点,一个好想的思路是我们使用深搜dfs从起点来出发不断搜索,遇到封锁点换到另一个路线,最终到达终点。我们开个变量记录到达终点的总路线。本题由于只是向右和向下并不需要标记位置。但是显然会超时。给一下深搜的代码:


import java.awt.FontFormatException;
import java.io.BufferedReader; 
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.AnnotatedWildcardType;
import java.math.BigInteger;
import java.net.DatagramPacket;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Spliterator.OfPrimitive;
import java.util.function.IntToDoubleFunction;
import java.util.function.LongBinaryOperator;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.management.relation.InvalidRelationTypeException;
import javax.print.attribute.standard.JobMessageFromOperator;
import javax.print.attribute.standard.JobPriority;
import javax.swing.plaf.ColorChooserUI;
import javax.swing.table.TableModel;
import javax.swing.text.TabSet;
import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec;
public class Main {
  public static void main(String[] args) throws IOException  {
Scanner sc=new Scanner(System.in);
BufferedReader br1=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw1=new PrintWriter(System.out);
String[] aStrings=br1.readLine().split(" ");
xx=Integer.parseInt(aStrings[0]);
yy=Integer.parseInt(aStrings[1]);
visited=new int[xx+1][yy+1];
int a=Integer.parseInt(aStrings[2]);
int b=Integer.parseInt(aStrings[3]);
visited[a][b]=-1;
int c,d;
int e=a-2;
int f=b-1;
if(e>=0&&e<=xx&&f>=0&&f<=yy) {
	visited[e][f]=-1;
}
int e1=a-1;
int f1=b-2;
if(e1>=0&&e1<=xx&&f1>=0&&f1<=yy) {
	visited[e1][f1]=-1;
}
int e2=a+1;
int f2=b-2;
if(e2>=0&&e2<=xx&&f2>=0&&f2<=yy) {
	visited[e2][f2]=-1;
}
int e3=a+2;
int f3=b-1;
if(e3>=0&&e3<=xx&&f3>=0&&f3<=yy) {
	visited[e3][f3]=-1;
}
int e4=a-2;
int f4=b+1;
if(e4>=0&&e4<=xx&&f4>=0&&f4<=yy) {
	visited[e4][f4]=-1;
}
int e5=a-1;
int f5=b+2;
if(e5>=0&&e5<=xx&&f5>=0&&f5<=yy) {
	visited[e5][f5]=-1;
}
int e6=a+1;
int f6=b+2;
if(e6>=0&&e6<=xx&&f6>=0&&f6<=yy) {
	visited[e6][f6]=-1;
}
int e7=a+2;
int f7=b+1;
if(e7>=0&&e7<=xx&&f7>=0&&f7<=yy) {
	visited[e7][f7]=-1;
}
dfs(0, 0);
System.out.println(answer);


  }
  public static int xx;
  public static int yy;
  public static int[] xx1= {0,-1,0,1};
  public static int[] yy1= {-1,0,1,0};
  public static int[][] visited;
  public static long answer=0;
public static void dfs(int a,int b) {
	if(a==xx&&b==yy) {
		answer++;
		return;
	}
	int c;
	for(c=2;c<=3;c++) {
		int x=a+xx1[c];
		int y=b+yy1[c];
		if(x>=0&&x<=xx&&y>=0&&y<=yy) {
			if(visited[x][y]!=-1) {
				dfs(x, y);
			}
		}
	}
}
		  
 }
 

超时了:

 这提示我们比赛时实在不会dp可以写dfs来骗分吗。(蓝桥专属)

(ps:蒟蒻只会dfs骗分,我哪会一开始就写dp还不是看了正解代码才会的)

回归正解,我们考虑dp做法。由于dfs超时了,我们考虑使用dp。因为本题

只能向右走和向下走,所以任何一个点,如果它可以被走到(这个点不是被封锁的点),那么它一定是从其上方的点和其左边的点走到的,那么我们的状态转移方程也就有了。

dp[i][j]=dp[i-1][j]+dp[i][j-1];

不过有鉴于我们的dp通常从1,1开始,所以我们默认将所有的位置都加上1,起点从(1,1)开始。顺便确定边界条件,我们直到起点为(1,1)那么我们从起点开始,假设终点就是(1,1)那肯定就只有一条路径。也就是说从起点开始路径就一条。根据我们的状态转移方程来判断,我们只需把(0,1)或(1,0)中的一个位置变为1即可。顺便如果遇到封锁点,我们直接把它赋值为0即可。

上代码:


import java.awt.FontFormatException;
import java.io.BufferedReader; 
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.AnnotatedWildcardType;
import java.math.BigInteger;
import java.net.DatagramPacket;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Spliterator.OfPrimitive;
import java.util.function.IntToDoubleFunction;
import java.util.function.LongBinaryOperator;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.management.relation.InvalidRelationTypeException;
import javax.print.attribute.standard.JobMessageFromOperator;
import javax.print.attribute.standard.JobPriority;
import javax.swing.plaf.ColorChooserUI;
import javax.swing.table.TableModel;
import javax.swing.text.TabSet;
import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec;
public class Main {
  public static void main(String[] args) throws IOException  {
Scanner sc=new Scanner(System.in);
BufferedReader br1=new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw1=new PrintWriter(System.out);
String[] aStrings=br1.readLine().split(" ");
xx=Integer.parseInt(aStrings[0]);
yy=Integer.parseInt(aStrings[1]);
visited=new long[xx+2][yy+2];
int a=Integer.parseInt(aStrings[2]);
int b=Integer.parseInt(aStrings[3]);
a=a+1;
b=b+1;
visited[a][b]=-1;
int c,d;
int e=a-2;
int f=b-1;
if(e>=0&&e<=xx+1&&f>=0&&f<=yy+1) {//这些if都是枚举封锁点,蒟蒻懒得写数组了,大家不要学我
	visited[e][f]=-1;
}
int e1=a-1;
int f1=b-2;
if(e1>=0&&e1<=xx+1&&f1>=0&&f1<=yy+1) {
	visited[e1][f1]=-1;
}
int e2=a+1;
int f2=b-2;
if(e2>=0&&e2<=xx+1&&f2>=0&&f2<=yy+1) {
	visited[e2][f2]=-1;
}
int e3=a+2;
int f3=b-1;
if(e3>=0&&e3<=xx+1&&f3>=0&&f3<=yy+1) {
	visited[e3][f3]=-1;
}
int e4=a-2;
int f4=b+1;
if(e4>=0&&e4<=xx+1&&f4>=0&&f4<=yy+1) {
	visited[e4][f4]=-1;
}
int e5=a-1;
int f5=b+2;
if(e5>=0&&e5<=xx+1&&f5>=0&&f5<=yy+1) {
	visited[e5][f5]=-1;
}
int e6=a+1;
int f6=b+2;
if(e6>=0&&e6<=xx+1&&f6>=0&&f6<=yy+1) {
	visited[e6][f6]=-1;
}
int e7=a+2;
int f7=b+1;
if(e7>=0&&e7<=xx+1&&f7>=0&&f7<=yy+1) {
	visited[e7][f7]=-1;
}
dp=new long[xx+2][yy+2];
dp[0][1]=1;

for(int i=1;i<=xx+1;i++) {
	for(int j=1;j<=yy+1;j++) {
		if(visited[i][j]==-1) {//把封锁点标记为-1,遇到封锁点我们赋值为0表示不能走
			dp[i][j]=0;
		}
		else
		dp[i][j]=dp[i-1][j]+dp[i][j-1];
	}
}
System.out.println(dp[xx+1][yy+1]);
//记得dp开long

  }
  public static int xx;
  public static int yy;
  public static long[][] visited;
  public static long[][] dp;
  public static int answer=0;


		  
 }
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值