java算法----动态规划(1)

java算法----动态规划(1),第1张


1.机器人行走问题

2.两人博弈问题

 

看上面这道题目,首先先用暴力递归的方法来写,暴力递归就是把机器人从m位置开始,经过k步的所有方法都列举出来,然后找出最终位置在p的点,数一数一共有多少这样的路径就是我们最终想要的答案。然后我们就开始自然尝试,会发现机器人在1位置的时候,其下一步只能去2号位置,当机器人到达n位置的时候,其下一步就只能去n-1这个位置,当机器人在其他位置的时候,可以往左走也可以往右走(自然尝试)。由这些想法之后我们就可以写出暴力递归的方法了。

	public static void main(String[] args) {
		// TODO Auto-generated method stub]
		System.out.println("===========暴力递归========");
		System.out.println("方法数为:"+MaxMethod(5,3,3,4));
		System.out.println("============动态规划===========");
		System.out.println("方法数为:"+Cmain(5,3,3,4));
	}
	public static int MaxMethod(int n,int k,int begin,int end) {
		if(k==0)
			return begin==end?1:0;
			if(begin==1)
				return MaxMethod(n,k-1,begin+1,end);
			else if(begin==n)
				return MaxMethod(n,k-1,begin-1,end);
			else
				return MaxMethod(n,k-1,begin+1,end)+MaxMethod(n,k-1,begin-1,end);
	}
	//根据暴力递归来改成动态规划
	public static int Cmain(int n,int k,int begin,int end) {
		if(n<1||k<0||begin<=0||begin>n|end<=0||end>n)
			return -1;
		int dp[][]=new int[n+1][k+1];
		for(int i=0;i<=n;i++) {
			for(int j=0;j<=k;j++)
				dp[i][j]=-1;
		}
		return MaxMethod1(n,k,begin,end,dp);
	}
	public static int MaxMethod1(int n,int k,int begin,int end,int dp[][]) {
		if(dp[begin][k]!=-1)
			return dp[begin][k];
		//之前没有算过
		int ans=0;
		if(k==0)
			ans=begin==end?1:0;
		else if(begin==1)
			ans=MaxMethod1(n,k-1,2,end,dp);
		else if(begin==n)
			ans=MaxMethod1(n,k-1,begin-1,end,dp);
		else
			ans=MaxMethod1(n,k-1,begin+1,end,dp)+MaxMethod1(n,k-1,begin-1,end,dp);
		dp[begin][k]=ans;
		return ans;
	}

 那么怎样由暴力递归改成动态规划呢?

首先我们要明白暴力递归和动态规划他们两的的区别在哪,暴力递归的过程就是把所有可能存在的方法都枚举一遍,在枚举的过程中即使有些信息我们已经得知了,暴力递归还会再次计算。由于这个原因,暴力递归的时间复杂度就比较高,而动态规划就是把已经算过的数据直接放到数组中,等下次在用这个数据的时候不在计算,直接取值即可。

这个就是递归的过程,我们可以看到,有些过程会重复进行。

怎样由暴力递归改成动态规划呢?

只需要将dp数组中的每个元素设成一个不会用到的值(如-1),在递归的时候判断相应格子上的数是不是-1,如果不是,证明其已经计算过了,直接返回使用就行了。

如何判断dp表的大小?

就看一直在变的量的大小。比如这一题,k和M(begin)一直在变,那么定义一个int dp[][]=new int[n+1][k+1];大的表就行。

两个人纸牌博弈问题

这也是一道比较经典的dp题型了。

 我们需要考虑的是先手和后手,因为两个人都绝顶聪明,所以两个人在选择纸牌的时候会考虑对方的得分情况,所以我们分别对先后和后手进行考虑。先手和后手都可以拿第一张牌,也可以拿最后一张牌

其不能为贪心策略(那张牌大选那一张),因为还要考虑接下来对手拿的牌。我们递归的策略就是先手拿第一张牌加上后手拿一张牌(后手拿的最优)剩下牌的最优和先手拿最后一张牌加上后手拿一张牌剩下牌的最优,算出这两种情况中最大的那种情况就是先手的最好得分。后手就是拿第一张牌或者最后一张牌,因为先手已经把最优的情况选择了,所以后手就只能选择这两种情况得分最小的那种情况。

其代码为:

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner srr=new Scanner(System.in);
		//System.out.println("请你输入一串数字,中间用空格分开,");
		int a[]= {1,23,34,54,65};
		//先手做多得分
		int p1=Fist_Play(a,0,4);
		int p2=Secound_Play(a,0,4);
		System.out.println("先手的最高得分"+p1);
		System.out.println("后手的最高得分"+p2);
		System.out.print("获胜者为:");
		if(p1>p2)
			System.out.println("先手");
		else if(p2>p1)
			System.out.println("后手");
		else
			System.out.println("平局");
		//动态规划
		System.out.println("---------动态规划--------");
		System.out.println(Cmain(a));
	}
	//先手的拿牌情况
	public static int Fist_Play(int a[],int left,int right) {
		if(right==left)
			return a[left];
		else {
			int p1=a[left]+Secound_Play(a,left+1,right);
			int p2=a[right]+Secound_Play(a,left,right-1);
			return Math.max(p1, p2);
		}
	}
	public static int Secound_Play(int a[],int left,int right) {
		if(right==left)
			return 0;//因为剩余的那一张牌已经被先手拿走了,此时数组内没有数字
		else{
			int p1=Fist_Play(a,left+1,right);
			int p2=Fist_Play(a,left,right-1);
			return Math.min(p1, p2);
		}
	}
	/*
	 * 由暴力递归改成动态规划需要注意三点
	 * 1.创建一个合适大小的dp表
	 * 2.找到这个dp表的初始值(看暴力递归的base,case)
	 * 3.填表的顺序(根据暴力递归递归的过程)
	 */
	public static int Cmain(int a[]) {
		int number=a.length;
		int fmap[][]=new int[number][number];
		int gmap[][]=new int[number][number];
		for(int i=0;ip2)
			System.out.println("先手");
		else if(p2>p1)
			System.out.println("后手");
		else
			System.out.println("平局");
		return Math.max(p1, p2);
	}
	public static int Fist_Play1(int a[],int left,int right,int dp1[][],int dp2[][]) {
		/*
		 * 根据left和right判断出这个dp表的大小为[a.length][a.length]
		 * if(right==left)
		 *	return a[left];
		 *根据这一句话来判断这个表初始值都哪些
		 */
		int k=0;
		for(int i=0;i

根据第一题的提示,生成一个dp数组,将算过的数放到表中,当要使用表中数据的时候直接调用就行了。填表的时候这个题也比较独特,两张表相互依赖,先手表的对角线 全为第一个纸牌的值,后手的对角线全为0.然后再根据递归,找到依赖将表填完就行了。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/756511.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-30
下一篇 2022-04-30

发表评论

登录后才能评论

评论列表(0条)