http://blog.csdn.net/sgnyyy/article/details/7490595
1 分治思想
(Divide-and-Conquer)
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
2 分治法解题的一般步骤
(1)分解( Divide ):,将要解决的问题划分成若干规模较小的同类问题;
(2)求解( Conquer):,当子问题划分得足够小时,用较简单的方法解决;
(3)合并(Combine):,按原问题的要求,将子问题的解逐层合并构成原问题的解。
通用框架:用递归的方式划分到一定程度
在递归求解子问题时同样要注意理清递归关系、递归出口、参数设置等问题。
divide_and_conquer(data)
{
if(data数据量较小)直接处理data得到结果,或者有个结束的判断,因为这个是在递归;
else
{
A.将data分为多个部分data1,data2,.....datan
并分别递归调用divide_and_conquer处理各个部分!
B.合并data1,data2,....datan处理之后的结果!
}
}
3 实例1---归并排序
思想:分而治之
每个递归过程涉及三个步骤:
1、 分解:把待排序的n个元素的序列分解成两个子序列,每个子序列包括n/2个元素。
2、 治理:把每个子序列分别调用归并排序MergeSort,进行递归操作。
3、 合并:合并两个排好序的子序列,生成排序结果
归并排序的工作原理:
1、 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列。
2、 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3、 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一个位置
4、 重复步骤3直到某一指针达到序列尾
5、 将另一序列剩下的所有元素直接复制到合并序列尾
代码:
//分治还有个明显的特点是left和right的下标,也就是说有一个分的标志
void Merge(int* array, int* tempararay, int left, int middle, int right)
{
//左指针尾
int leftend = middle-1;
//右指针头
int rightstart = middle;
int tempIndex = left;
//数组合并后的length长度
int tempLength = right - left + 1;
//相当于排序,把临时的结果放入到tempararay中
while( (left <= leftend) && (rightstart <= right) )
{
if(array[left]<array[rightstart])
{
tempararay[tempIndex++] = array[left++];
}
else
{
tempararay[tempIndex++] = array[rightstart++];
}
}
//判断左序列是否结束
while(left <= leftend)
tempararay[tempIndex++] = array[left++];
while(rightstart <= right)
tempararay[tempIndex++] = array[rightstart++];
//交换临时排序的数据
for(int i=0; i<tempLength; i++)
{
array[right] = tempararay[right];
cout<<array[right]<<" ";
right--;
}
if(tempLength)
cout<<endl;
}
void MergeSort(int* array, int* temparray, int left, int right)
{
if(left < right)
{
//1、分解划分成前后两部分
int middle = (left+right)/2;
//2、对分解治理
MergeSort(array, temparray, left, middle);
//2、对分解治理
MergeSort(array, temparray, middle+1, right);
//3、合并
Merge(array, temparray, left, middle+1, right);
}
}
int main()
{
int a[] = {13,7,8,3,60,50,4};
int len = sizeof(a)/sizeof(int);
//需要申请一块临时的内存保存排序结果
int* b = new int[len];
MergeSort(a,b,0,len-1);
for(int i=0; i<len; i++)
{
cout<<a[i]<<",";
}
}
4 快速排序
分而治之
//一趟排序,每一次一趟之后,前半部分是小的,后半部分是大的
int Partition(int *array, int low, int high)
{
//*array = *(array+low);
int pivotKey = *(array+low);
while(low<high)
{
while(low<high && *(array+high)>pivotKey)
--high;
*(array+low) = *(array+high);
while(low<high && *(array+low)<pivotKey)
++low;
*(array+high) = *(array+low);
}
*(array+low) = pivotKey;
return low;
}
//再写分治法的代码:
void QSort(int *array, int low, int high)
{
if(low<high)
{
//1. 分解
int middle = Partition(array, low, high);
//2. 递归求解
QSort(array, low , middle-1);
QSort(array, middle+1, high);
//3. 合并:由于分解出的两个字序列是就地进行的,所以不需要再次合并
}
}
void BinarySort(int *array, int length, int data)
{
QSort(array,0,length-1);
}
5 循环赛日程
n个选手的比赛日程可以通过n/2个选手的比赛日程来确定,递归调用,直到剩下两个选手的时候,比赛日程就可以很容易的确定
先计算出一部分,然后另一部分赋值
void gametable(int k)
{
int a[100][100];
int n,temp,i,j,p,t;
n=2;
a[1][1]=1;a[1][2]=2;
a[2][1]=2;a[2][2]=1;
for(t=1;t<k;t++)
{
temp=n;n=n*2;
for(i=temp+1;i<=n;i++)
for(j=1;j<=temp;j++)
a[i][j]=a[i-temp][j]+temp;
for(i=1;i<=temp;i++)
{
for(j=temp+1;j<=n;j++)
{
a[i][j]=a[i+temp][(j+temp)%n];
}
}
for(i=temp+1;i<=n;i++)//将左上角元素抄到右下角
for(j=temp+1;j<=n;j++)
a[i][j]=a[i-temp][j-temp];
}
cout<<n<<endl;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
6 二分搜索法
int BinarySearch(int a[], int &x, int left, int right)
{
while(left < right)
{
int middle = (left + right)/2;
if(a[middle] == x) return middle;
if(a[middle] < x) right = middle - 1;
else left = middle + 1;
}
}
7 最近点对问题
1)蛮力法:
计算每两个之间的距离,然后比较,也就是计算(n-1)与n个元素之间的比较
2)分治法:
a. 找中线把n个元素分成左右两部分分别求得两边的最短距离,然后取两者中的最小者,计为len
b. 在中线两边分别取len的距离。记录该距离范围内点的个数,中线左边有L个元素,右边有R个元素。
c. 求左边元素到右边元素的距离看其是否小于之前记录的len,小则记录下来。
d. 此时的右边元素只取y值和左边元素y值距离小于1的(减少循环次数)。
e. 循环结束即可找到最小的距离
以下是思想 与 程序框架
a[]坐标已有序
float test(CPoint a[],int begin,int end,int len)
{
if(len>2)
{
mid=(end-begin)>>1;
int d1=test(a,begin,mid);
int d2=test(a,mid,end);
int d=d1<d2?d1:d2;
CPoint* b=cal(a,d);
float temp=cal_T(b,d);
return temp<d?temp:d;
}
else//len==2
{//仅仅有两个点 PointA PointB
return Distance(a,begin,end);
}
}
8 Strassen矩阵乘法
9 大整数乘法
10:使用分治法求解数组的第k大数
引申问题:在数组A【】中,找一个元素a[i],使得小于a[i]的放到其左边,大于的放在其右边。
void test_1(int *a,int index,int len)
{
if(index>=len)
return;
swap(a[index],a[len-1]);
int j=-1;
int i=0;
for(int idx=0;idx<len;idx++)
{
if(a[idx]<a[len-1])
{
swap(a[idx],a[++j]);
}
}
swap(a[++j],a[len-1]);
}
void print(int a[],int len)
{
for(int i=0;i<len;i++)
printf("%d",a[i]);
printf("\n");
}
int a[]={6,2,3,1,0,5};
int a1[]={6,2,3,1,0,5};
void test_2(int *a,int index,int len)
{
int key=a[index];
swap(a[index],a[0]);
print(a,len);
int j=len-1;
int i=0;
while(i<j)
{
while(i<j&&a[j]>=key)
{
j--;
}
if(i<j)
a[i++]=a[j];
while(i<j&&a[i]<key)
{
i++;
}
if(i<j)
a[j--]=a[i];
}
a[i]=key;
}
以下是查找第k个大的数字:
void print(int a[],int len)
{
for(int i=0;i<len;i++)
printf("%d",a[i]);
printf("\n");
}
int a[]={6,2,3,1,0,5};
int a1[]={6,2,3,1,0,5};
int test_2(int *a,int index,int len,int begin)
{
int key=a[index+begin];
swap(a[index+begin],a[begin]);
//print(a,len);
int j=begin+len-1;
int i=begin;
while(i<j)
{
while(i<j&&a[j]>=key)
{
j--;
}
if(i<j)
a[i++]=a[j];
while(i<j&&a[i]<key)
{
i++;
}
if(i<j)
a[j--]=a[i];
}
a[i]=key;
return i;
}
#include <time.h>
int FindMaxK(int *a,int begin,int end,int k)
{
int randomPos=rand()%(end-begin+1);
int len=end-begin+1;
int temp=test_2(a,randomPos,end-begin+1,begin);
print(a,6);
if(k==len-temp+begin)
{
return a[temp];
}
else if(k<len-temp)
{
FindMaxK(a,temp+1,end,k);
}
else
FindMaxK(a,begin,temp-1,k-(len-temp));
}
11 全排列问题与dfs解决组合问题
bool isOK(char* str,int idx,int i)
{
for(int j=idx;j<i;j++)
{
if(str[j]==str[i])
return false;
}
return true;
}
void perm(int idx,int num,int cur,char* str)
{
if(cur==num)
{
for(int i=0;i<num;i++)
printf("%c",str[i]);
printf("\n");
}
else
{
for(int i=idx;i<num;i++)
{
if(isOK(str,idx,i))
{
swap(str[idx],str[i]);
perm(idx+1,num,cur+1,str);
swap(str[idx],str[i]);
}
}
}
}
char str[]={'1','2','2'};
//perm(0,sizeof(str),0,str);
void zuhe(int cur,int num,std::vector<int> col,int idx)
{
if(cur==4)
{
std::vector<int> temp;
temp=col;
std::vector<int>::iterator iter=col.begin();
for(;iter!=col.end();iter++)
printf("%d",*iter);
printf("\n");
return;
}
else
{
for(int i=idx;i<num;i++)
{
col.push_back(i);
zuhe(cur+1,num,col,i+1);
col.pop_back();
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<int> col;
zuhe(0,9,col,0);
return 0;
}
12 递归解决八皇后问题