动态规划与分治策略

本文通过二分查找、最大连续部分和、缓存优化斐波那契数列及城墙顶刷漆问题,深入探讨分治和动态规划在算法中的应用。详细介绍了如何使用这两种策略来提高效率并解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划与分治策略

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) 最后走对面格
+2fa(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));
	}
}

}

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

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值