分治算法

来源:互联网 发布:diy婚庆域名 编辑:程序博客网 时间:2024/06/05 16:26

一、基本概念

将一个复杂的问题分解为多个相同或相似的子问题,通过递归的方式,将子问题继续分解,直到子问题容易解决。

二、特征

1.分治法所能解决的问题一般具有以下几个特征:

1. 该问题的规模缩小到一定的程度就可以容易地解决2. 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。3. 利用该问题分解出的子问题的解可以合并为该问题的解;4. 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

2.特征解释

1. 第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;2. 第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归;3. 第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法;4. 第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。

三、使用场景

问题规模线性增长,带动的计算量为非线性增长,且满足分治算法的三个特征(2、3、4),则可使用分支算法。

四、矩阵乘法

1.矩阵乘法公式

C(i,j)=k=1nA(i,k)×B(k,j)

2. 是否符合分治算法

1.条件(1)显然满足2.条件(2)(3)满足,证明如下:

C=A×B=[A0A2A1A3]×[B0B2B1B3]=[A0×B0+A1×B2A2×B0+A3×B2A0×B1+A1×B3A2×B1+A3×B3]

A0A1A2A3为(n/2)阶矩阵(N为A矩阵的阶)
B0B1B2B3为(n/2)阶矩阵(N为B矩阵的阶)

3. 使用分治算法的思想

将N×N阶的矩阵转换为(N/2)×(N/2)阶的矩阵,采用递归的方式不断缩小矩阵相乘时矩阵的阶数,直到方便求解。

4. C# 代码实现

/// <summary>/// 直接求两个矩阵的乘积/// C[i,j] = Sum(A[i,k] * B[k,j]) (k = 1~n)/// </summary>/// <param name="p"></param>/// <param name="q"></param>/// <returns></returns>int[,] DirectMultiplication(int[,] p,int[,] q){    /// p的列数 == q的行数 才能相乘    if (p.GetLength(1) != q.GetLength(0))    {        return null;    }    int[,] result = new int[p.GetLength(0),q.GetLength(1)];    for (int i = 0; i < p.GetLength(0); i++)    {        for (int j = 0; j < q.GetLength(1); j++)        {            result[i,j] = 0;            for (int k = 0; k < p.GetLength(1); k++)            {                result[i,j] += p[i,k] * q[k,j];            }        }    }    return result;}/// <summary>/// 递归计算矩阵相乘/// </summary>/// <param name="p"></param>/// <param name="q"></param>/// <param name="n"></param>/// <returns></returns>int[,] DivideAndConquer(int[,] p, int[,] q, int n){    if (!IsPowerValueOfTwo(n))    {        return DirectMultiplication(p, q);    }    else    {        if (n == 2)        {            return DirectMultiplication(p, q);        }        if (n > 2)        {            int[,] result = new int[n,n];            int[][,] pMatrix = PartitionMatrix(p, n);            int[][,] qMatrix = PartitionMatrix(q, n);            int[][,] rMatrix = PartitionMatrix(result, n);            /// 核心            /// A[0] * B[0] + A[1] * B[2]            /// A[0] * B[1] + A[1] * B[3]            /// A[2] * B[0] + A[3] * B[2]            /// A[2] * B[1] + A[3] * B[3]            for (int i = 0; i < rMatrix.GetLength(0); i++)            {                int row = 2 * (i / 2);                int col = i % 2;                rMatrix[i] = AddMatrix(DivideAndConquer(pMatrix[row], qMatrix[col], n / 2),                                        DivideAndConquer(pMatrix[row + 1], qMatrix[col + 2], n / 2),                                        n / 2);            }            /// 合并矩阵            result = MergeMatrix(rMatrix, n / 2);            return result;        }        else        {            return null;        }    }}/// <summary>/// 是否为2的幂次方/// </summary>/// <param name="n"></param>/// <returns></returns>bool IsPowerValueOfTwo(int n){    while (true)    {        if (n == 1) return true;        if (n % 2 == 1) return false;        else n = n / 2;    }}/// <summary>/// 矩阵加法/// </summary>/// <param name="p"></param>/// <param name="q"></param>/// <param name="n"></param>/// <returns></returns>int[,] AddMatrix(int[,] p, int[,] q, int n){    int[,] result = new int[n,n];    for (int i = 0; i < n; i++)    {        for (int j = 0; j < n; j++)        {            result[i,j] = p[i,j] + q[i,j];        }    }    return result;}/// <summary>/// 分解矩阵/// </summary>/// <param name="matrix"></param>/// <param name="n"></param>/// <returns></returns>int[][,] PartitionMatrix(int[,] matrix,int n){    int newLen = n/2;    /// 初始化数组    int[][,] pMatrix = new int[4][,];    for (int i = 0; i < 4; i++)    {        pMatrix[i] = new int[newLen, newLen];    }    for (int k = 0; k < 4; k++)    {        int startRow = (k / 2) * newLen;        int startCol = (k % 2) * newLen;        for (int i = 0; i < newLen; i++)        {            for (int j = 0; j < newLen; j++)            {                pMatrix[k][i,j] = matrix[i + startRow,j + startCol];            }        }    }    return pMatrix;}/// <summary>/// 合并矩阵/// </summary>/// <param name="rMatrix"></param>/// <param name="n"></param>/// <returns></returns>int[,] MergeMatrix(int[][,] rMatrix,int n){    int[,] matrix = new int[2 * n,2 * n];    for (int k = 0; k < rMatrix.GetLength(0); k++)    {        int startRow = (k / 2) * n;        int startCol = (k % 2) * n;        for (int i = 0; i < n; i++)        {            for (int j = 0; j < n; j++)            {                matrix[i + startRow,j + startCol] = rMatrix[k][i,j];            }        }    }    return matrix;}
原创粉丝点击