分治(分而治之):
分治法将原问题划分成若干个规模较小而结构与原问题相同或相似的子问题
然后分别解决这些子问题
最后合并子问题的解
即可得到原问题的解
即三个步骤:
①分解
②解决
③合并
注意:分治法分解出的子问题应当是相互独立、没有交叉的。
如果存在两个子问题有交叉部分,那么不应该使用分治法解决
从广义上讲:分治法分解的子问题个数只要大于0即可
但严格来说:子问题个数为1的情况为减治(n的阶乘)
而把子问题个数大于1的情况称为分治(Fibonacci数列)
可以用递归的手段实现,也可以用非递归的手段实现
n的阶乘
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 10005
int F(int n)
{
if(n==0)
return 1;
else
return F(n-1)*n;
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n",F(n));
return 0;
}
Fibonacci数列
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 10005
int F(int n)
{
if(n==0||n==1)
return 1;
else
return F(n-1)+F(n-2);
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n",F(n));
return 0;
}
重点是递归边界和递归式
全排列,一般把1~n这n个整数按某个顺序摆放的结果称为这n个整数的一个排列
而全排列指这n个整数能形成的所有排列
例如对1、2、3这三个整数来说
(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)、(3,2,1)就是1~3全排列
现在需要实现按字典序从小到大的顺序输出1~n的全排列
其中(a1,a2,…,an)的字典序小于(b1,b2,…,bn)是指存在一个i
使得a1=b1,a2=b2,…,ai-1=bi-1、ai<bi成立
从递归的角度去考虑,如果把问题描述成“输出1~n这n个整数的全排列”
那么它就可以分为若干个问题
“输出以1开头的全排列”、“输出以2开头的全排列”…“输出以n开头的全排列”
于是可以设定一个数组P,用来存放当前的排列;
再设定一个散列数组hashTable
其中hashTable[x]当整数x已经在数组P时为true
#include<cstdio>
#define maxn 11
int n,P[maxn],hashTable[maxn]={false};
void generateP(int index)
{
if(index==n+1)
{
for(int i=1;i<=n;i++)
{
printf("%d",P[i]);
}
printf("\n");
return;
}
for(int x=1;x<=n;x++)
{
if(hashTable[x]==false)
{
P[index]=x;
hashTable[x]=true;
generateP(index+1);
hashTable[x]=false;
}
}
}
int main()
{
n=3;
generateP(1);
return 0;
}
另一种:
#include<cstdio>
#include <iostream>
using namespace std;
void permutation(char* a,int k,int m)
{
int i,j;
if(k == m)
{
for(i=0;i<=m;i++)
cout<<a[i];
cout<<endl;
}
else
{
for(j=k;j<=m;j++)
{
//printf("j1=%d,k=%d\n",j,k);
swap(a[j],a[k]);
//printf("j=%c k=%c\n",a[j],a[k]);
//printf("j22=%d,k=%d\n",j,k);
permutation(a,k+1,m);
//printf("j3=%d,k=%d\n",j,k);
swap(a[j],a[k]);
//printf("j4=%d,k=%d\n",j,k);
//printf("jkkk=%c k1=%c\n",a[j],a[k]);
}
}
}
int main(void)
{
char a[] = "abc";
cout<<a<<"所有全排列的结果为:"<<endl;
permutation(a,0,2);
//system("pause");
return 0;
}
但其实使用ATL更为简单
STL有一个函数next_permutation(),它的作用是如果对于一个序列,存在按照字典排序后这个排列的下一个排列,那么就返回true且产生这个排列,否则返回false。注意,为了产生全排列,这个序列要是有序的,也就是说要调用一次sort。
代码:
#include "iostream"
#include "algorithm"
using namespace std;
void permutation(char* str,int length)
{
sort(str,str+length);
do
{
for(int i=0;i<length;i++)
cout<<str[i];
cout<<endl;
}while(next_permutation(str,str+length));
}
int main(void)
{
char str[] = "acb";
cout<<str<<"所有全排列的结果为:"<<endl;
permutation(str,3);
system("pause");
return 0;
}
对数1,2,3,4,5要实现全排序。要求4必须在3的左边,其它的数位置随意。
思路:首先使用上面的2种方法之一实现全排列,然后对全排列进行筛选,筛选出4在3左边的排列。
#include "iostream"
#include "algorithm"
using namespace std;
void permutation(int* a,int length)
{
int i,flag;
sort(a,a+length);
do
{
for(i=0;i<length;i++)
{
if(a[i]==3)
flag=1;
else if(a[i]==4) //如果3在4的左边,执行完代码,flag就是2
flag=2;
}
if(flag==1) //如果4在3的左边,执行完代码,flag就是1
{
for(i=0;i<length;i++)
cout<<a[i];
cout<<endl;
}
}while(next_permutation(a,a+length));
}
int main(void)
{
int i,a[5];
for(i=0;i<5;i++)
a[i]=i+1;
printf("%d以内所有4在3左边的全排列结果为:\n",i);
permutation(a,5);
system("pause");
return 0;
}