动态规划与分治学习总结

  • 6.1 二分查找

二分查找
半开区间, 左闭右开 例如:[1,5) [5,10)
package 分治与动态规划;

public class 二分查找
{
	public static void main(String[] args)
	{
		int[] arr = { 1, 2, 3, 4, 5 };
		System.out.println(f(arr, 5));
	}

	private static int f(int[] arr, int i)
	{
		if (i > arr.length)
		{
			return -1;
		}
		return f(arr, i, 0, arr.length);
	}

	/**
	 * 
	 * @param arr
	 * @param find
	 *            要找的
	 * @param begin
	 *            左闭
	 * @param end
	 *            右开
	 */
	private static int f(int[] arr, int find, int begin, int end)
	{
		if (end - begin == 1)
		{
			if (find != arr[begin])
			{
				return -1;
			}
			return begin;
		}
		int hi = (begin + end) / 2;
		if (arr[hi] > find)
		{
			return f(arr, find, begin, hi);
		} else if ((arr[hi] < find))
		{
			return f(arr, find, hi, end);
		}
		return hi;
	}
}


  • 6.2 最大连续部分和
最大连续部分和
数组中整数有正有负
求连续一子段,使得和最大化
2,4,-7,5,2,-1,2,-4,3
最大连续段:5,2,-1,2
最大和为8

package 分治与动态规划;

public class 分治最大连续部分和
{

	public static void main(String[] args)
	{
		int[] arr = { 2, 4, -7, 5, 2, -1, 2, -4, 3 };
		System.out.println(f(arr, 0, arr.length));
	}

	private static int f(int[] arr, int begin, int end)
	{
		if (end - begin == 1)
		{
			if (arr[begin] > 0)
			{
				return arr[begin];
			}
			return 0;
		}
		int k = (begin + end) / 2;
		int left = f(arr, begin, k);
		int right = f(arr, k, end);

		int leftk = 0;
		int sum = 0;
		// 向左扩展
		for (int i = k - 1; i >= begin; i--)
		{
			sum += arr[i];
			if (sum >= leftk)
			{
				leftk = sum;
			}
		}

		int rightk = 0;
		sum=0;
		// 向左扩展
		for (int i = k; i < end; i++)
		{
			sum += arr[i];
			if (sum >= rightk)
			{
				rightk = sum;
			}
		}
		
		int kz=leftk+rightk;
		return Math.max(kz, Math.max(right, left));
	}

}

  • 6.3缓存结果
缓存结果
比如斐波拉契数列
f(9) = f(8) + f(7)
=(f(7)+f(6)) + (f(6)+f(5))
=((f(6)+f(5))+(f(5)+f(4))) + ((f(5)+f(4))+(f(4)+f(3)))
= ....
同样参数的函数算了很多遍

解决方法:
1缓存(按需存放)
2仔细设计计算次序,可以用数组


package 分治与动态规划;

import java.util.HashMap;
import java.util.Map;

public class 取球博弈代码用缓存
{

	static private Map<Integer, Boolean> result=new HashMap<>();
	public static void main(String[] args)
	{
		int i=1055;
		System.out.println(i+" "+f(i));
	}

	private static boolean f(int i)
	{
		if (i==0)
		{//最后一个球被对方取走了,那我就赢了
			return true;
		}
		if (result.get(i)!=null)
		{
			return result.get(i);
		}
		try
		{
			if (i>=1&&f(i-1)==false)return true;
			if (i>=3&&f(i-3)==false)return true;
			if (i>=7&&f(i-7)==false)return true;
			if (i>=8&&f(i-8)==false)return true;					
		} finally
		{
			result.put(i, true);
		}
		result.put(i, false);
		return false;
	}
}

  • 6..4动态规划
动态规划

城墙顶刷漆
X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图所示)
现需要把这些格子刷上保护漆。

你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)

比如:a d b c e f 就是合格的刷漆顺序。
c e f d a b 是另一种合适的方案。

当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
输入数据为一个正整数(不大于1000)
输出数据为一个正整数。

例如:
用户输入:
2
程序应该输出:
24

再例如:
用户输入:
3
程序应该输出:
96

再例如:
用户输入:
22
程序应该输出:
359635897

锦囊1
fb(n) 从某个边缘格子,到与它对面的格子结束,
fb(n) = fb(n-1) * 2 

锦囊2:
fa(n) 从某个边缘格子开始的所有情况(再晚走这格就来不及了)
fa(n) = fb(n) 最后走对面格
+2*fa(n-1) 第1步走对面格
+4*fa(n-2) 第2步走对面格

package 分治与动态规划;

public class 城墙顶刷漆
{
	static final long M = 1000000007;

	public static long fb(int n)
	{
		if (n == 1)
		{
			return 1;
		}
		return fb(n - 1) % M * 2 % M;
	}

	public static long fa(int n)
	{
		if (n == 1)
		{
			return 1;
		}
		if (n == 2)
		{
			return 6;
		}
		return (fb(n) % M + 2 * fa(n - 1) % M + 4 * fa(n - 2) % M) % M;
	}

	public static long fk(int i, int n)
	{
		return ((fb(i) % M * fa(n - i) % M) % M * 2 % M + (fb(n - i + 1) % M * fa(i - 1) % M) % M * 2 % M) % M * 2 % M;
	}

	public static long f(int n)
	{
		if (n == 1)
		{
			return 2;
		}
		long sum = fa(n) * 4 % M;
		for (int i = 2; i < n; i++)
		{
			sum = (sum % M + fk(i, n) % M) % M;
		}
		return sum % M;
	}

	public static void main(String[] args)
	{
		for (int i = 1; i < 30; i++)
		{
			System.out.println(i + " " + f(i));
		}
	}

}

  • 6..5作业
作业
环形涂色
如图,组成环形的格子需要涂3种颜色。
它们的编号分别是1~14
相邻的格子不能用相同的颜色。
涂色方案的数目是:24576

当格子数目为50的时候,求涂色方案总数。

package 分治与动态规划;


public class 环形涂色
{
	static final int BlUE=1;
	static final int RED=2;
	static final int YELLOW=3;
	static int count;
	public static void main(String[] args)
	{
		int colorArrays[]=new int[14];
		dfs(0,colorArrays);
		System.out.println(count);
	}
	private static void dfs(int i, int[] colorArrays)
	{
		if (i==colorArrays.length)
		{
			if (check(colorArrays)==true)
			{
				count++;
//				System.out.println(Arrays.toString(colorArrays));
			}
			return;
		}
		for (int j = BlUE; j <= YELLOW; j++)
		{
			int old=colorArrays[i];
			colorArrays[i]=j;
			
			dfs(i+1, colorArrays);
			
			colorArrays[i]=old;
		}
		
	}
	private static boolean check(int[] colorArrays)
	{
		for (int i = 1; i < colorArrays.length-1; i++)
		{
			if (colorArrays[i]==colorArrays[i+1]||colorArrays[i]==colorArrays[i-1])
			{
				return false;
			}
		}
		if (colorArrays[0]==colorArrays[colorArrays.length-1])
		{
			return false;
		}
		return true;
	}

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值