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

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

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

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

java 复制代码
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。因为本题

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

java 复制代码
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即可。

上代码:

java 复制代码
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;


		  
 }
 
相关推荐
徐浪老师36 分钟前
C语言实现冒泡排序:从基础到优化全解析
c语言·算法·排序算法
hr_net38 分钟前
图论入门编程
算法·图论
李小白6638 分钟前
各种排序算法
数据结构·算法·排序算法
浪前41 分钟前
排序算法之冒泡排序篇
数据结构·算法·排序算法
小黄编程快乐屋43 分钟前
各个排序算法基础速通万字介绍
java·算法·排序算法
PeterClerk44 分钟前
图论基础知识
算法·深度优先·图论
是糖不是唐1 小时前
代码随想录算法训练营第五十八天|Day58 图论
c语言·算法·图论
Eric.Lee20213 小时前
数据集-目标检测系列- 装甲车 检测数据集 armored_vehicles >> DataBall
python·算法·yolo·目标检测·装甲车检测
材料苦逼不会梦到计算机白富美3 小时前
贪心算法-区间问题 C++
java·c++·贪心算法
慢慢来_5 小时前
【力扣热题100】[Java版] 刷题笔记-448. 找到所有数组中消失的数字
笔记·算法·leetcode