分治法

概念:

     分治法是编程界排名前五的重要算法之一,但是它本身并不是一种具体的算法,也没有典型的数据结构,而是一种编程思想,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
     适合用分治法求解的问题是通常在递归的每一步都会生成全新的子问题。


方法:

分:分解。分解步骤将问题划分为一些子问题,子问题的形式与原问题一样,只是规模够小。
治:解决。解决步骤递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。当子问题足够大,需要递归求解时,我们称之为递归情况。当子问题变得足够小,不再需要递归时,我们说递归已经触底,进入了基本情况
合:合并。合并步骤将子问题的解组合为原问题的解。


算法经典实例:

1、最大子数组问题: 给定n个整数(可能为负数)组成的序列a[1],a[2]…a[n],求该序列a[i],a[i+1]…a[j]的子段和的最大值。
分析: 1): 暴力求解找出所有的组合,共有C(n,2)种选择,时间复杂度Θ(n^2)。2): 利用分治法求解最大字数组的思想是把每一个数组一分为二,每次考虑最大字数组所在的三种可能情况:跨中点,中点左侧,中点右侧。算法的计算量主要在于跨中点这种情况,中点单侧主要是控制划分深度,所以每一层计算复杂度是Θ(n),二分以后深度为logn,因此分治法的计算复杂度是Θ(nlogn)。

#include<iostream>
#include<vector>
#include<string>
using namespace std;
struct ret
{
   int begin;
   int end;
   int sum;
};
ret  FindMaxCrossSubarray(int *array,int low, int high) {
   int mid = (low + high) / 2;
   //右
   int sumright = array[mid+1];
   int tempsum = array[mid + 1];
   int end = mid+1;
   for(int i= mid+2; i <= high; i++){
   	tempsum += array[i];
   	if (tempsum > sumright){
   		sumright = tempsum;
   		end = i;
   	}
   }
   //左
   int sumleft = array[mid];//应该选一个最小值
   tempsum = array[mid];
   int start = mid;
   for (int i = mid-1; i >= low; i--) {
   	tempsum += array[i];
   	if (tempsum > sumleft) {
   		sumleft = tempsum;
   		start = i;
   	}
   }
   ret temp;
   temp.begin = start;
   temp.end = end;
   temp.sum = sumleft + sumright;
   return temp;
}
ret FindMaxSubarray(int *array,int low,int high) {
   if (low == high)//递归触底
   {ret temp;
   temp.begin = low;
   temp.end = high;
   temp.sum = array[low];
   return temp;
   };
   //分治合
   int mid = (low + high) / 2;
   ret left=FindMaxSubarray(array,low, mid);
   ret right=FindMaxSubarray(array, mid+1, high);
   ret cross=FindMaxCrossSubarray(array,low, high);

   if (left.sum >= right.sum && left.sum >= cross.sum)
   	return left;
   if (right.sum >= left.sum && right.sum >= cross.sum)
   	return right;
   return cross;
}
int main(){
   int temp[9] = { -2,1,-3,4,-1,2,1,-5,4};
   ret result = FindMaxSubarray(temp,0,8);
   cout << result.begin << endl;
   cout << result.end << endl;
   cout << result.sum << endl;
   getchar();
}

2、归并排序:

void mergesort(int *array,int begin, int mid, int end) {
	if (begin >= end)
		return;
	int *array1 = (int *)malloc(sizeof(int)*(mid-begin+1));
	for (int i = 0; i <= mid - begin; i++) {
		array1[i] = array[begin+i];
	}
	int *array2 = (int *)malloc(sizeof(int)*(end - mid));
	for (int i = 0; i <= end-mid-1; i++) {
		array2[i] = array[mid+1 + i];
	}
	int a1 = 0;
	int a2 = 0;
	for (int i = begin; i <= end; i++) {
		if (((array1[a1] <= array2[a2])&&a1<= mid - begin)||(a2>end - mid - 1))
			array[i] = array1[a1++];
		else
			array[i] = array2[a2++];
	}
}
void merge(int *array, int begin, int end) {
	if (begin >= end)
		return;
	int mid = (begin + end) / 2;
	merge(array, begin, mid);
	merge(array, mid+1, end);
	mergesort(array, begin, mid, end);
}
int main() {
	int temp[] = {5,3,4,7,8,1,2,9,10,6};
	merge(temp,0,9);
	for (int i = 0; i < 10; i++)
	{
		cout << temp[i] << " ";
	}
	getchar();
}

3、施特拉森(strassen)矩阵问题:

1)普通解法:o(n^3)

SQUARE-MATRIX-MULTIPLY(A, B)
n = A.rows
let C be a new nxn matrix
for i = 1 to n
  for j = 1 to n
      c[i][j] = 0
      for k = 1 to n
          c[i][j] += a[i][k] * b[k][j]
return C

2) strassen算法:
在这里插入图片描述

  1. 首先把每个矩阵分割为4份:
    对于二阶矩阵
    a11	a12		    b11	b12	
A =	a21	a22	    B =	b21	b22
  1. 接着,计算7次矩阵乘法:
    x1 = (a11 + a22) * (b11 + b22);
    x2 = (a21 + a22) * b11;
    x3 = a11 * (b12 - b22);
    x4 = a22 * (b21 - b11);
    x5 = (a11 + a12) * b22;
    x6 = (a21 - a11) * (b11 + b12);
    x7 = (a12 - a22) * (b21 + b22);
  2. 最后,根据这7个结果就可以计算出C矩阵:
    C11 = X5 + X4 - X2 + X6
    C12 = X1 + X2
    C21 = X3 + X4
    C22 = X5 + X1 - X3 - X7
    根据以上的方法,我们就可以计算4阶矩阵了,先将4阶矩阵A和B划分成四块2阶矩阵,分别利用公式计算它们的乘积,再使用步骤1和3来计算出最后结果。
        ma11	ma12			mb11	mb12	
A4 =	ma21	ma22	   B4 =	mb21	mb22

其中

        a11	a12				a13	a14				b11	b12				b13	b14	
ma11 =	a21	a22	 ;  ma12 =	a23	a24;	mb11 =	b21	b22;	mb12 =	b23	b24
        a31	a32				a33	a34				b31	b32				b33	b34	
ma21 =	a41	a42  ;	ma22 =	a43	a44;	mb21 =	b41	b42;	mb22 =	b43	b44
// 计算2X2矩阵
void Multiply2X2(float& fOut_11, float& fOut_12, float& fOut_21, float& fOut_22,
					float f1_11, float f1_12, float f1_21, float f1_22,
					float f2_11, float f2_12, float f2_21, float f2_22)
{
	const float x1((f1_11 + f1_22) * (f2_11 + f2_22));
	const float x2((f1_21 + f1_22) * f2_11);
	const float x3(f1_11 * (f2_12 - f2_22));
	const float x4(f1_22 * (f2_21 - f2_11));
	const float x5((f1_11 + f1_12) * f2_22);
	const float x6((f1_21 - f1_11) * (f2_11 + f2_12));
	const float x7((f1_12 - f1_22) * (f2_21 + f2_22));

	fOut_11 = x1 + x4 - x5 + x7;
	fOut_12 = x3 + x5;
	fOut_21 = x2 + x4;
	fOut_22 = x1 - x2 + x3 + x6;
}

// 计算4X4矩阵
void Multiply(CLAYMATRIX& mOut, const CLAYMATRIX& m1, const CLAYMATRIX& m2)
{
	float fTmp[7][4];

	// (ma11 + ma22) * (mb11 + mb22)
	Multiply2X2(fTmp[0][0], fTmp[0][1], fTmp[0][2], fTmp[0][3],
					m1._11 + m1._33, m1._12 + m1._34, m1._21 + m1._43, m1._22 + m1._44,
					m2._11 + m2._33, m2._12 + m2._34, m2._21 + m2._43, m2._22 + m2._44);

	// (ma21 + ma22) * mb11
	Multiply2X2(fTmp[1][0], fTmp[1][1], fTmp[1][2], fTmp[1][3],
					m1._31 + m1._33, m1._32 + m1._34, m1._41 + m1._43, m1._42 + m1._44,
					m2._11, m2._12, m2._21, m2._22);

	// ma11 * (mb12 - mb22)
	Multiply2X2(fTmp[2][0], fTmp[2][1], fTmp[2][2], fTmp[2][3],
					m1._11, m1._12, m1._21, m1._22,
					m2._13 - m2._33, m2._14 - m2._34, m2._23 - m2._43, m2._24 - m2._44);

	// ma22 * (mb21 - mb11)
	Multiply2X2(fTmp[3][0], fTmp[3][1], fTmp[3][2], fTmp[3][3],
					m1._33, m1._34, m1._43, m1._44,
					m2._31 - m2._11, m2._32 - m2._12, m2._41 - m2._21, m2._42 - m2._22);

	// (ma11 + ma12) * mb22
	Multiply2X2(fTmp[4][0], fTmp[4][1], fTmp[4][2], fTmp[4][3],
					m1._11 + m1._13, m1._12 + m1._14, m1._21 + m1._23, m1._22 + m1._24,
					m2._33, m2._34, m2._43, m2._44);

	// (ma21 - ma11) * (mb11 + mb12)
	Multiply2X2(fTmp[5][0], fTmp[5][1], fTmp[5][2], fTmp[5][3],
					m1._31 - m1._11, m1._32 - m1._12, m1._41 - m1._21, m1._42 - m1._22,
					m2._11 + m2._13, m2._12 + m2._14, m2._21 + m2._23, m2._22 + m2._24);

	// (ma12 - ma22) * (mb21 + mb22)
	Multiply2X2(fTmp[6][0], fTmp[6][1], fTmp[6][2], fTmp[6][3],
					m1._13 - m1._33, m1._14 - m1._34, m1._23 - m1._43, m1._24 - m1._44,
					m2._31 + m2._33, m2._32 + m2._34, m2._41 + m2._43, m2._42 + m2._44);

	// 第一块
	mOut._11 = fTmp[0][0] + fTmp[3][0] - fTmp[4][0] + fTmp[6][0];
	mOut._12 = fTmp[0][1] + fTmp[3][1] - fTmp[4][1] + fTmp[6][1];
	mOut._21 = fTmp[0][2] + fTmp[3][2] - fTmp[4][2] + fTmp[6][2];
	mOut._22 = fTmp[0][3] + fTmp[3][3] - fTmp[4][3] + fTmp[6][3];

	// 第二块
	mOut._13 = fTmp[2][0] + fTmp[4][0];
	mOut._14 = fTmp[2][1] + fTmp[4][1];
	mOut._23 = fTmp[2][2] + fTmp[4][2];
	mOut._24 = fTmp[2][3] + fTmp[4][3];

	// 第三块
	mOut._31 = fTmp[1][0] + fTmp[3][0];
	mOut._32 = fTmp[1][1] + fTmp[3][1];
	mOut._41 = fTmp[1][2] + fTmp[3][2];
	mOut._42 = fTmp[1][3] + fTmp[3][3];

	// 第四块
	mOut._33 = fTmp[0][0] - fTmp[1][0] + fTmp[2][0] + fTmp[5][0];
	mOut._34 = fTmp[0][1] - fTmp[1][1] + fTmp[2][1] + fTmp[5][1];
	mOut._43 = fTmp[0][2] - fTmp[1][2] + fTmp[2][2] + fTmp[5][2];
	mOut._44 = fTmp[0][3] - fTmp[1][3] + fTmp[2][3] + fTmp[5][3];
}

完整版:
int Strassen(int N, int **MatrixA, int **MatrixB, int **MatrixC)
{

       int HalfSize = N/2;
       int newSize = N/2;

       if ( N <= 64 )//choosing the threshhold is extremely important, try N<=2 to see the result
       {
           MUL(MatrixA,MatrixB,MatrixC,N);
       }
       else
       {
   		int** A11;
   		int** A12;
   		int** A21;
   		int** A22;

   		int** B11;
   		int** B12;
   		int** B21;
   		int** B22;

   		int** C11;
   		int** C12;
   		int** C21;
   		int** C22;

   		int** M1;
   		int** M2;
   		int** M3;
   		int** M4;
   		int** M5;
   		int** M6;
   		int** M7;
   		int** AResult;
   		int** BResult;

           //making a 1 diminsional pointer based array.
   		A11 = new int *[newSize];
   		A12 = new int *[newSize];
   		A21 = new int *[newSize];
   		A22 = new int *[newSize];

   		B11 = new int *[newSize];
   		B12 = new int *[newSize];
   		B21 = new int *[newSize];
   		B22 = new int *[newSize];

   		C11 = new int *[newSize];
   		C12 = new int *[newSize];
   		C21 = new int *[newSize];
   		C22 = new int *[newSize];

   		M1 = new int *[newSize];
   		M2 = new int *[newSize];
   		M3 = new int *[newSize];
   		M4 = new int *[newSize];
   		M5 = new int *[newSize];
   		M6 = new int *[newSize];
   		M7 = new int *[newSize];

   		AResult = new int *[newSize];
   		BResult = new int *[newSize];

   		int newLength = newSize;

           //making that 1 diminsional pointer based array , a 2D pointer based array
   		for ( int i = 0; i < newSize; i++)
   		{
   			A11[i] = new int[newLength];
   			A12[i] = new int[newLength];
   			A21[i] = new int[newLength];
   			A22[i] = new int[newLength];

   			B11[i] = new int[newLength];
   			B12[i] = new int[newLength];
   			B21[i] = new int[newLength];
   			B22[i] = new int[newLength];

   			C11[i] = new int[newLength];
   			C12[i] = new int[newLength];
   			C21[i] = new int[newLength];
   			C22[i] = new int[newLength];

   			M1[i] = new int[newLength];
   			M2[i] = new int[newLength];
   			M3[i] = new int[newLength];
   			M4[i] = new int[newLength];
   			M5[i] = new int[newLength];
   			M6[i] = new int[newLength];
   			M7[i] = new int[newLength];

   			AResult[i] = new int[newLength];
   			BResult[i] = new int[newLength];


   		}
   		//splitting input Matrixes, into 4 submatrices each.
           for (int i = 0; i < N / 2; i++)
           {
               for (int j = 0; j < N / 2; j++)
               {
                   A11[i][j] = MatrixA[i][j];
                   A12[i][j] = MatrixA[i][j + N / 2];
                   A21[i][j] = MatrixA[i + N / 2][j];
                   A22[i][j] = MatrixA[i + N / 2][j + N / 2];

                   B11[i][j] = MatrixB[i][j];
                   B12[i][j] = MatrixB[i][j + N / 2];
                   B21[i][j] = MatrixB[i + N / 2][j];
                   B22[i][j] = MatrixB[i + N / 2][j + N / 2];

               }
           }

           //here we calculate M1..M7 matrices .
           //M1[][]
           ADD( A11,A22,AResult, HalfSize);
           ADD( B11,B22,BResult, HalfSize);
           Strassen( HalfSize, AResult, BResult, M1 ); //now that we need to multiply this , we use the strassen itself .


           //M2[][]
           ADD( A21,A22,AResult, HalfSize);              //M2=(A21+A22)B11
           Strassen(HalfSize, AResult, B11, M2);       //Mul(AResult,B11,M2);

           //M3[][]
           SUB( B12,B22,BResult, HalfSize);              //M3=A11(B12-B22)
           Strassen(HalfSize, A11, BResult, M3);       //Mul(A11,BResult,M3);

           //M4[][]
           SUB( B21, B11, BResult, HalfSize);           //M4=A22(B21-B11)
           Strassen(HalfSize, A22, BResult, M4);       //Mul(A22,BResult,M4);

           //M5[][]
           ADD( A11, A12, AResult, HalfSize);           //M5=(A11+A12)B22
           Strassen(HalfSize, AResult, B22, M5);       //Mul(AResult,B22,M5);


           //M6[][]
           SUB( A21, A11, AResult, HalfSize);
           ADD( B11, B12, BResult, HalfSize);             //M6=(A21-A11)(B11+B12)
           Strassen( HalfSize, AResult, BResult, M6);    //Mul(AResult,BResult,M6);

           //M7[][]
           SUB(A12, A22, AResult, HalfSize);
           ADD(B21, B22, BResult, HalfSize);             //M7=(A12-A22)(B21+B22)
           Strassen(HalfSize, AResult, BResult, M7);     //Mul(AResult,BResult,M7);

           //C11 = M1 + M4 - M5 + M7;
           ADD( M1, M4, AResult, HalfSize);
           SUB( M7, M5, BResult, HalfSize);
           ADD( AResult, BResult, C11, HalfSize);

           //C12 = M3 + M5;
           ADD( M3, M5, C12, HalfSize);

           //C21 = M2 + M4;
           ADD( M2, M4, C21, HalfSize);

           //C22 = M1 + M3 - M2 + M6;
           ADD( M1, M3, AResult, HalfSize);
           SUB( M6, M2, BResult, HalfSize);
           ADD( AResult, BResult, C22, HalfSize);


           //at this point , we have calculated the c11..c22 matrices, and now we are going to
           //put them together and make a unit matrix which would describe our resulting Matrix.
           for (int i = 0; i < N/2 ; i++)
           {
               for (int j = 0 ; j < N/2 ; j++)
               {
                   MatrixC[i][j] = C11[i][j];
                   MatrixC[i][j + N / 2] = C12[i][j];
                   MatrixC[i + N / 2][j] = C21[i][j];
                   MatrixC[i + N / 2][j + N / 2] = C22[i][j];
               }
           }

           // dont forget to free the space we alocated for matrices,
   		for (int i = 0; i < newLength; i++)
   		{
   			delete[] A11[i];delete[] A12[i];delete[] A21[i];
   			delete[] A22[i];

   			delete[] B11[i];delete[] B12[i];delete[] B21[i];
   			delete[] B22[i];
   			delete[] C11[i];delete[] C12[i];delete[] C21[i];
   			delete[] C22[i];
   			delete[] M1[i];delete[] M2[i];delete[] M3[i];delete[] M4[i];
   			delete[] M5[i];delete[] M6[i];delete[] M7[i];
   			delete[] AResult[i];delete[] BResult[i] ;
   		}
   			delete[] A11;delete[] A12;delete[] A21;delete[] A22;
   			delete[] B11;delete[] B12;delete[] B21;delete[] B22;
   			delete[] C11;delete[] C12;delete[] C21;delete[] C22;
   			delete[] M1;delete[] M2;delete[] M3;delete[] M4;delete[] M5;
   			delete[] M6;delete[] M7;
   			delete[] AResult;
   			delete[] BResult ;


       }//end of else


   return 0;
}

int ADD(int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
   for ( int i = 0; i < MatrixSize; i++)
   {
       for ( int j = 0; j < MatrixSize; j++)
       {
           MatrixResult[i][j] =  MatrixA[i][j] + MatrixB[i][j];
       }
   }
   return 0;
}

int SUB(int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
   for ( int i = 0; i < MatrixSize; i++)
   {
       for ( int j = 0; j < MatrixSize; j++)
       {
           MatrixResult[i][j] =  MatrixA[i][j] - MatrixB[i][j];
       }
   }
   return 0;
}

int MUL( int** MatrixA, int** MatrixB, int** MatrixResult, int MatrixSize )
{
   for (int i=0;i<MatrixSize ;i++)
       {
             for (int j=0;j<MatrixSize ;j++)
             {
                  MatrixResult[i][j]=0;
                  for (int k=0;k<MatrixSize ;k++)
                  {
                         MatrixResult[i][j]=MatrixResult[i][j]+MatrixA[i][k]*MatrixB[k][j];
                  }
             }
       }
   return 0;
}

void FillMatrix( int** MatrixA, int** MatrixB, int length)
{
   for(int row = 0; row<length; row++)
   {
       for(int column = 0; column<length; column++)
       {

          MatrixB[row][column] = (MatrixA[row][column] = rand() %5);
           //matrix2[row][column] = rand() % 2;//ba hazfe in khat 50% afzayeshe soorat khahim dasht
       }

   }
}
void PrintMatrix(int **MatrixA,int MatrixSize)
{
   cout<<endl;
      for(int row = 0; row<MatrixSize; row++)
   	{
   		for(int column = 0; column<MatrixSize; column++)
   		{


   			cout<<MatrixA[row][column]<<"\t";
   			if ((column+1)%((MatrixSize)) == 0)
   				cout<<endl;
   		}

   	}
      cout<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值