分治法——全排列、整数划分、最近点对问题、棋盘覆盖

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YL970302/article/details/88560013

一、分治法的求解过程:

(1)划分:既然是分治,当然需要把规模为n的原问题划分为k个规模较小的子问题,并尽量使这k个子问题的规模大致相同。

(2)求解子问题:各子问题的解法与原问题的解法通常是相同的,可以用递归的方法求解各个子问题,有时递归处理也可以用循环来实现。

(3)合并:把各个子问题的解合并起来,合并的代价因情况不同有很大差异,分治算法的有效性很大程度上依赖于合并的实现。

典型的递推方程:

迭代法可求得

典型案例:

一、全排列问题:

问题:R是由n个元素构成的序列集合,R={r1, r2, … ,rn},求R全排列perm(R)

问题理解:

(1) R中只有1个元素{r},则perm(R)=(r)

(2) R中只有2个元素{r1, r2},则

      perm(R)=(r1)perm(R1)(r2)perm(R2)

      其中,Ri=R-{ri}

(3) R中有3个元素{ r1, r2, r3},则

    perm(R)=(r1)perm(R1)(r2)perm(R2)(r3)perm(R3)

分析:

思想:

依次将待排列的数组的后n-1个元素与第一个元素交换,则每次递归处理的都是后n-1个元素的全排列。当数组元素仅有一个时为此递归算法的出口。

代码展示:

#include<iostream>
using namespace std;

void Perm(int *arr, int k, int m) //m是数组最后一个元素的下标
{
	if(k == m)
	{
		for(int i = 0; i<m; i++)
		{
			cout<<arr[i];
		}
		cout<<endl;
	}
	else
	{
		for(int i=k; i<m; i++)
		{
			swap(arr[k],arr[i]);
			Perm(arr,k+1,m);
			swap(arr[k],arr[i]);
		}
		
	}
}

int main()
{
	int arr[] = {1,2,3};
	Perm(arr,0,sizeof(arr)/sizeof(arr[0]));

	return 0;
}

二、整数划分

问题:将给定正整数n表示成一系列正整数之和

n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥1k≥1

求正整数n的不同划分个数p(n)

举例:

正整数6有如下11种不同的划分:

6;

5+1;

4+2, 4+1+1;

3+3, 3+2+1, 3+1+1+1;

2+2+2, 2+2+1+1, 2+1+1+1+1;

1+1+1+1+1+1;

代码展示:

int Q(int n, int m) //n是要划分的数,最大加数n1不大于m
{
	if( (n < 1) || (m < 1) )
	{
		return 0;
	}
	if((n == 1) || (m == 1))
	{
		return 1;
	}
	if(n < m)
	{
		return Q(n,n);
	}
	if(n == m)
	{
		return Q(n,m-1) + 1;
	}
	return Q(n,m-1) + Q(n-m,m);

}

int main()
{
	int m = 5;
	int n = 5;

	cout<<Q(n, m)<<endl;

	return 0;
}

问题扩展:苹果装盘

三、最近点对问题

问题:给定平面上的n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对之间的距离最小。

常规思想:只要将每一点与其它n-1个点的距离算出,找出其中距离最小的两点即可。问题:效率太低,T(n)=O(n2)

分治思想:将平面上n个点的集合S划分为两个子集S1S2,每个子集约n/2个点,然后在每个子集中寻找最接近点对。

问题在于合并:如何根据子集中的最接近点对求得原集合中的最接近点对。

解决步骤:

bool Cpair2(S,d) {

     n=|S|;

     if (n < 2) {d=; return false;}

1m=S中各点x间坐标的中位数;

      构造S1S2

      //S1={p∈S|x(p)<=m},

      //S2={p∈S|x(p)>m}

2Cpair2(S1,d1);

      Cpair2(S2,d2);

3dm=min(d1,d2);

4、设P1S1中距垂直分割线l的距离在dm之内的所有点组成的集合;

      P2S2中距分割线l的距离在dm之内所有点组成的集合;

      将P1P2中点依其y坐标值排序;

      并设XY是相应的已排好序的点列;

5、通过扫描X以及对于X中每个点检查Y中与其距离在dm之内的所有点(最多6)可以完成合并;

      当X中的扫描指针逐次向上移动时,Y中的扫描指针可在宽为2dm的区间内移动;

      设dl是按这种扫描方式找到的点对间的最小距离;

6d=min(dm,dl);

      return true;}

四、棋盘覆盖

k>0时,将2k×2k棋盘分割为42k-1×2k-1 子棋盘(a)所示。

特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如 (b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为棋盘1×1

猜你喜欢

转载自blog.csdn.net/YL970302/article/details/88560013
今日推荐