1.分治算法的策略
对于一个大规模的问题a(若问题a规模较小则直接解决),分成b个小规模问题,这些问题相互独立,并且可用递归等方式解决,最后这些问题的解集合得到原问题的解。
2.分治算法求解经典问题
- 合并排序
- 快速排序
- 大整数乘法
- 二分搜索
- 线性时间选择
- Strassen矩阵乘法
- 汉诺塔
- 最接近点对问题
- 棋盘覆盖
- 循环赛日程表
3.应用题--最大子数组问题(求得股票收益最大化)
天数 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
股票价格 | 100 | 113 | 110 | 85 | 105 | 102 | 86 | 63 | 81 | 101 | 94 | 106 | 101 | 79 | 94 | 90 | 97 |
价格变化 | 13 | -3 | -25 | 20 | -3 | -16 | -23 | 18 | 20 | -7 | 12 | -5 | -22 | 15 | -4 | 7 |
3.1暴力求解法
internal class Program
{
static void Main(string[] args)
{
int[] price = {100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97};
int[] priceChange = new int[price.Length-1];
for (int i = 0; i < priceChange.Length; i++)
{
priceChange[i] = price[i + 1] - price[i];
}
int total = priceChange[0];
int startIndex = 0;
int endIndex = 0;
for(int i = 0; i < priceChange.Length; i++)
{
//以i为起点获取子数组
for(int j = i; j < priceChange.Length; j++)
{
//由i j确定子数组
int temp = 0;
for (int a = i; a < j + 1; a++)
{
//计算收益
temp += priceChange[a];
}
if(total<temp)
{
//保存最大收益及标志位
total = temp;
startIndex = i;
endIndex = j;
}
}
}
Console.WriteLine(startIndex);
Console.WriteLine(endIndex);
Console.WriteLine("获取最大收益应该在第{0}天买入,第{1}天卖出",startIndex+1,endIndex+2);
}
}
3.2分治法求解
internal class Program
{
//最大子数组结构体
struct MaxA
{
public int startIndex;
public int endIndex;
public int total;
}
static void Main(string[] args)
{
int[] price = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 79, 94, 90, 97 };
int[] priceChange = new int[price.Length - 1];//价格波动数组
for (int i = 0; i < priceChange.Length; i++)
{
priceChange[i] = price[i + 1] - price[i];
}
MaxA maxA = GetMaxA(0, priceChange.Length-1, priceChange);
Console.WriteLine(maxA.startIndex);
Console.WriteLine(maxA.endIndex);
Console.WriteLine("获取最大收益应该在第{0}天买入,第{1}天卖出", maxA.startIndex + 1, maxA.endIndex + 2);
}
static MaxA GetMaxA(int start,int end,int[] a)//用于取得a数组中 start到end之间的最大子数组
{
//Console.WriteLine(end);
if (start==end)
{
MaxA a0;
a0.startIndex = start;
a0.endIndex = end;
a0.total = a[start];
return a0;
}
int mid = (start + end) / 2;
MaxA a1 = GetMaxA(start, mid, a);
MaxA a2 = GetMaxA(mid+1, end, a);
//从start,mid中找最大子数组i,mid
int total1 = a[mid];
int startIndex = mid;
int temp = 0;
for(int i = mid; i >= start; i--)
{
temp += a[i];
if (temp > total1)
{
total1 = temp;
startIndex = i;
}
}
//从mid+1,end中找最大子数组mid+1,j
int total2 = a[mid + 1];
int endIndex = mid + 1;
temp = 0;
for (int j = mid + 1; j <= end; j++)
{
temp += a[j];
if (temp > total2)
{
total2 = temp;
endIndex = j;
}
}
MaxA a3;
a3.startIndex = startIndex;
a3.endIndex = endIndex;
a3.total = total1 + total2;
if (a1.total >= a2.total && a1.total >= a3.total)
{
return a1;
}
else if(a2.total>=a1.total && a2.total >= a3.total)
{
return a2;
}
else
{
return a3;
}
}
}