- 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;
}
}