1.分治法基本模板
divide-and-comquer(P)
{
if(|P|<=n0)
adhoc(P);
divide P into smaller subinstances P1,P2,...,Pk;
for(i=1;i<=k;i++)
yi=divide-and-comquer(Pi);
return merge(y1,...,yk);
}
a.一般是递归出口
b.将原问题分割成若干子问题,子问题与原问题相同,规模略小
c.合并子问题的解(不是所有分治都有这个)
2.递归与非递归的转换记录
a.尾递归转非递归(一般先写好递归版,再用栈模拟)(本质:还是自顶而下)
尾递归在原问题转换成若干子问题之后,不再合并子问题的解,递归是最后的语句,递归之后不再有操作返回值或局部变量的表达式。
1.循环外压栈初始变量
2.循环以栈空为条件
3.循环内先出栈,恢复局部变量值
4.递归出口处,仍然编写递归出口处代码,由continue代替return来打断余下操作
5.用恢复的局部变量值操作
6.遇到递归处,改成压栈当前局部变量
7.出循环
b.线性(一般)递归转非递归
若用栈模拟递归,保存当前局部变量用以代替递归,但是递归之后,又需要用这些改变后的局部变量(或递归返回值)做子问题的合并,这个对我来说比较难做。所以换个方向,思考记录如下:
1.尾递归转非递归的本质还是自顶而下的处理问题,所以可以用栈轻易模拟
2.非尾递归可以自底而上,来转化递归
尾递归转非递归: 3.棋盘覆盖,4.快速排序
非尾递归转非递归:5.strassen矩阵乘法,6.合并排序
3.棋盘覆盖
a.递归版
#include<iostream>
#include<vector>
using namespace std;
vector< vector<int> > a;
static int tile=1;
void chessBoard(int startx,int starty,int msize,int x,int y)
{
if(msize==1)
{
return;
}
else
{
int g=tile++;//只能用局部变量来赋值,直接用静态变量,递归返回后,余下伪特殊方块的赋值就出问题了。
int tempx=(x-startx)/(msize/2);
int tempy=(y-starty)/(msize/2);
if(tempx==0&&tempy==0)
{
chessBoard(startx,starty,msize/2,x,y);
}
else
{
a[startx+msize/2-1][starty+msize/2-1]=g;
chessBoard(startx,starty,msize/2,startx+msize/2-1,starty+msize/2-1);
}
if(tempx==0&&tempy==1)
{
chessBoard(startx,starty+msize/2,msize/2,x,y);
}
else
{
a[startx+msize/2-1][starty+msize/2]=g;
chessBoard(startx,starty+msize/2,msize/2,startx+msize/2-1,starty+msize/2);
}
if(tempx==1&&tempy==0)
{
chessBoard(startx+msize/2,starty,msize/2,x,y);
}
else
{
a[startx+msize/2][starty+msize/2-1]=g;
chessBoard(startx+msize/2,starty,msize/2,startx+msize/2,starty+msize/2-1);
}
if(tempx==1&&tempy==1)
{
chessBoard(startx+msize/2,starty+msize/2,msize/2,x,y);
}
else
{
a[startx+msize/2][starty+msize/2]=g;
chessBoard(startx+msize/2,starty+msize/2,msize/2,startx+msize/2,starty+msize/2);
}
}
}
int main()
{
//初始化棋盘a,特殊元素赋值0,其余元素赋值-1
int n;
cout<<"please input n!"<<endl;
cin>>n;
vector<int> temp;
for(int j=0;j<n;j++)
{
temp.push_back(-1);
}
for(int i=0;i<n;i++)
{
a.push_back(temp);
}
cout<<"please input the special box coordinates!"<<endl;
int x,y;
cin>>x>>y;
a[x][y]=0;
//特殊元素赋值0,伪特殊元素均大于0,未被标记的均为-1
chessBoard(0,0,n,x,y);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<a[i][j]<<"\t";
}
cout<<endl;
}
}
b.非递归版
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
typedef struct Node
{
public:
int startx;
int starty;
int msize;
int x;
int y;
};
vector< vector<int> > a;//存放棋盘
stack<Node> s;//存放临时变量
void chessBoard(int startx,int starty,int msize,int x,int y)
{
Node temp;//临时变量
int g=1;
temp.startx=startx;
temp.starty=starty;
temp.msize=msize;
temp.x=x;
temp.y=y;
s.push(temp);//初始状态压栈
while(!s.empty())//栈空为循环终止判断条件
{
Node temp2=s.top();//出栈,恢复局部变量
s.pop();
if(temp2.msize==1)//递归出口处,return用continue代替,打断余下操作
{
continue;
}
if((temp2.x-temp2.startx)<temp2.msize/2&&(temp2.y-temp2.starty)<temp2.msize/2)
{
temp.startx=temp2.startx;
temp.starty=temp2.starty;
temp.msize=temp2.msize/2;
temp.x=temp2.x;
temp.y=temp2.y;
s.push(temp);//先用递归写,写非递归时递归处,用栈保存局部变量,其余各处也一样
}
else
{
temp.startx=temp2.startx;
temp.starty=temp2.starty;
temp.msize=temp2.msize/2;
temp.x=temp2.startx+temp2.msize/2-1;
temp.y=temp2.starty+temp2.msize/2-1;
s.push(temp);
if(a[temp2.startx+temp2.msize/2-1][temp2.starty+temp2.msize/2-1]==-1)
a[temp2.startx+temp2.msize/2-1][temp2.starty+temp2.msize/2-1]=g;
}
if((temp2.x-temp2.startx)<temp2.msize/2&&(temp2.y-temp2.starty)>temp2.msize/2)
{
temp.startx=temp2.startx;
temp.starty=temp2.starty+temp2.msize/2;
temp.msize=temp2.msize/2;
temp.x=temp2.x;
temp.y=temp2.y;
s.push(temp);
}
else
{
temp.startx=temp2.startx;
temp.starty=temp2.starty+temp2.msize/2;
temp.msize=temp2.msize/2;
temp.x=temp2.startx+temp2.msize/2-1;
temp.y=temp2.starty+temp2.msize/2;
s.push(temp);
if(a[temp2.startx+temp2.msize/2-1][temp2.starty+temp2.msize/2]==-1)
a[temp2.startx+temp2.msize/2-1][temp2.starty+temp2.msize/2]=g;
}
if((temp2.x-temp2.startx)>temp2.msize/2&&(temp2.y-temp2.starty)<temp2.msize/2)
{
temp.startx=temp2.startx+temp2.msize/2;
temp.starty=temp2.starty;
temp.msize=temp2.msize/2;
temp.x=temp2.x;
temp.y=temp2.y;
s.push(temp);
}
else
{
temp.startx=temp2.startx+temp2.msize/2;
temp.starty=temp2.starty;
temp.msize=temp2.msize/2;
temp.x=temp2.startx+temp2.msize/2;
temp.y=temp2.starty+temp2.msize/2-1;
s.push(temp);
if(a[temp2.startx+temp2.msize/2][temp2.starty+temp2.msize/2-1]==-1)
a[temp2.startx+temp2.msize/2][temp2.starty+temp2.msize/2-1]=g;
}
if((temp2.x-temp2.startx)>temp2.msize/2&&(temp2.y-temp2.starty)>temp2.msize/2)
{
temp.startx=temp2.startx+temp2.msize/2;
temp.starty=temp2.starty+temp2.msize/2;
temp.msize=temp2.msize/2;
temp.x=temp2.x;
temp.y=temp2.y;
s.push(temp);
}
else
{
temp.startx=temp2.startx+temp2.msize/2;
temp.starty=temp2.starty+temp2.msize/2;
temp.msize=temp2.msize/2;
temp.x=temp2.startx+temp2.msize/2;
temp.y=temp2.starty+temp2.msize/2;
s.push(temp);
if(a[temp2.startx+temp2.msize/2][temp2.starty+temp2.msize/2]==-1)
a[temp2.startx+temp2.msize/2][temp2.starty+temp2.msize/2]=g;
}
g++;
}
return;
}
int main()
{
int n;
cout<<"please input n!"<<endl;
cin>>n;
vector<int> temp;
for(int j=0;j<n;j++)
{
temp.push_back(-1);
}
for(int i=0;i<n;i++)
{
a.push_back(temp);
}
cout<<"please input the special box coordinates!"<<endl;
int x,y;
cin>>x>>y;
a[x][y]=0;
chessBoard(0,0,n,x,y);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<a[i][j]<<"\t";
}
cout<<endl;
}
return 0;
}
4.快速排序(随机快速排序:随机在left~right之间选择一个主元,再将主元与最左(右)元素互换位置,其他一切照旧)(按各主元对称的序列,快排效果最好)
a.递归版
#include<iostream>
#include<vector>
using namespace std;
int qSortOne(vector<int> &p,int left,int right)
{
int a=p[left];
while(left<right)
{
while(a<p[right])
{
right--;
}
p[left]=p[right];
p[right]=a;
while(a>p[left])
{
left++;
}
p[right]=p[left];
p[left]=a;
}
return left;
}
void qSort(vector<int> &w,int left,int right)
{
if(left<right)
{
int start=qSortOne(w,left,right);
qSort(w,left,start-1);
qSort(w,start+1,right);
}
}
int main()
{
vector<int> a;
int temp;
while(cin>>temp)
{
a.push_back(temp);
}
qSort(a,0,a.size()-1);
for(int i=0;i<a.size();i++)
{
cout<<a[i]<<"\t";
}
cout<<endl;
}
b.非递归版
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
typedef struct Node
{
int left;
int right;
};
stack<Node> s;
int qSortOne(vector<int> &p,int left,int right)
{
int a=p[left];
while(left<right)
{
while(a<p[right])
{
right--;
}
p[left]=p[right];
p[right]=a;
while(a>p[left])
{
left++;
}
p[right]=p[left];
p[left]=a;
}
return left;
}
void qSort(vector<int> &w,int left,int right)
{
Node temp;
temp.left=left;
temp.right=right;
s.push(temp);
while(!s.empty())
{
Node temp1=s.top();
s.pop();
if(temp1.left<temp1.right)
{
int start=qSortOne(w,temp1.left,temp1.right);
temp.left=temp1.left;
temp.right=start-1;
s.push(temp);
temp.left=start+1;
temp.right=temp1.right;
s.push(temp);
}
}
}
int main()
{
vector<int> a;
int temp;
while(cin>>temp)
{
a.push_back(temp);
}
qSort(a,0,a.size()-1);
for(int i=0;i<a.size();i++)
{
cout<<a[i]<<"\t";
}
cout<<endl;
}
5.strassen矩阵乘法
a.非递归版
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n;
cout<<"please input n!"<<endl;
cin>>n;
vector< vector<int> > A;//A作为乘数矩阵A,和存储结果矩阵C
vector< vector<int> > B;
cout<<"please input matrix A!"<<endl;
for(int i=0;i<n;i++)
{
int temp1;
vector<int> temp2;
for(int j=0;j<n;j++)
{
cin>>temp1;
temp2.push_back(temp1);
}
A.push_back(temp2);
}
cout<<"please input matrix B!"<<endl;
for(int i=0;i<n;i++)
{
int temp1;
vector<int> temp2;
for(int j=0;j<n;j++)
{
cin>>temp1;
temp2.push_back(temp1);
}
B.push_back(temp2);
}
cout<<"count matrix C!"<<endl;
for(int i=0;i<n;i=i+2)
{
vector<int> M;
for(int j=0;j<n;j=j+2)
{
M.push_back(A[i][j]*(B[i][j+1]-B[i+1][j+1]));
M.push_back((A[i][j]+A[i][j+1])*B[i+1][j+1]);
M.push_back((A[i+1][j]+A[i+1][j+1])*B[i][j]);
M.push_back(A[i+1][j+1]*(B[i+1][j]-B[i][j]));
M.push_back((A[i][j]+A[i+1][j+1])*(B[i][j]+B[i+1][j+1]));
M.push_back((A[i][j+1]-A[i+1][j+1])*(B[i+1][j]+B[i+1][j+1]));
M.push_back((A[i][j]-A[i+1][j])*(B[i][j]+B[i][j+1]));
A[i][j]=M[4]+M[3]-M[1]+M[5];
A[i][j+1]=M[0]+M[1];
A[i+1][j]=M[2]+M[3];
A[i+1][j+1]=M[4]+M[0]-M[2]-M[6];
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cout<<A[i][j]<<"\t";
}
cout<<endl;
}
}
6.合并排序
a.递归版
#include<iostream>
#include<vector>
#include<cstdlib>
using namespace std;
int random(int s,int e)
{
return s+rand()%(e-s+1);
}
void mergeD(vector<int> &a,vector<int> &b,int l,int mid,int r)
{
int i=l;
int j=mid+1;
while(i<=mid&&j<=r)
{
if(a[i]<a[j])
{
b.push_back(a[i++]);
}
else
{
b.push_back(a[j++]);
}
}
while(i<=mid)
{
b.push_back(a[i++]);
}
while(j<=r)
{
b.push_back(a[j++]);
}
}
void copyD(vector<int> &a,vector<int> &b,int l,int r)
{
for(int i=l;i<=r;i++)
{
a[i]=b[i-l];
}
}
void mergeSort(vector<int> &d,int l,int r)
{
if(l<r)
{
int i=(r+l)/2;
mergeSort(d,l,i);
mergeSort(d,i+1,r);
vector<int> b;
mergeD(d,b,l,i,r);
copyD(d,b,l,r);
}
}
int main()
{
vector<int> data;
int temp;
cin>>temp;
for(int i=0;i<temp;i++)
{
data.push_back(random(0,40));
}
for(int i=0;i<temp;i++)
{
cout<<"data["<<i<<"]: "<<data[i]<<"\t";
}
cout<<"\n"<<endl;
mergeSort(data,0,temp-1);
for(int i=0;i<temp;i++)
{
cout<<"data["<<i<<"]: "<<data[i]<<"\t";
}
cout<<endl;
}
b.非递归版
#include<iostream>
#include<vector>
#include<cstdlib>
#include<stack>
using namespace std;
int random(int s,int e)
{
return s+rand()%(e-s+1);
}
void mergeD(vector<int> &a,vector<int> &b,int l,int mid,int r)
{
int i=l;
int j=mid+1;
while(i<=mid&&j<=r)
{
if(a[i]<a[j])
{
b.push_back(a[i++]);
}
else
{
b.push_back(a[j++]);
}
}
while(i<=mid)
{
b.push_back(a[i++]);
}
while(j<=r)
{
b.push_back(a[j++]);
}
}
void copyD(vector<int> &a,vector<int> &b,int l,int r)
{
for(int i=l;i<=r;i++)
{
a[i]=b[i-l];
}
}
//尾递归转非递归用栈模拟(本质上还是自顶而下)
//线性递归转非递归用栈模拟比较困难,那么就换种思路,自底而上
void mergeSort(vector<int> &d)
{
int size=2;//排序小组大小
int n=d.size();
int left;
int right;
while(size<=n)
{
for(left=0;left+size-1<=n-1;left=left+size)
{
right=left+size-1;
vector<int> b;
mergeD(d,b,left,(right+left)/2,right);
copyD(d,b,left,right);
}
if(right<n-1)
{
right=n-1;
vector<int> b;
mergeD(d,b,left,left+size/2-1,right);
copyD(d,b,left,right);
}
size=size*2;
}
size=size/2;
if(size!=n)
{
left=0;
right=n-1;
vector<int> b;
mergeD(d,b,left,left+size-1,right);
copyD(d,b,left,right);
}
}
int main()
{
vector<int> data;
int temp;
cin>>temp;
for(int i=0;i<temp;i++)
{
data.push_back(random(0,40));
}
for(int i=0;i<temp;i++)
{
cout<<"data["<<i<<"]: "<<data[i]<<"\t";
}
cout<<"\n"<<endl;
mergeSort(data);
for(int i=0;i<temp;i++)
{
cout<<"data["<<i<<"]: "<<data[i]<<"\t";
}
cout<<endl;
}
7.线性时间选择(在序列中找出第k小的数(中位数等等))
a.寻找第k小元素(随机划分线性时间选择)
#include<iostream>
#include<vector>
#include<cstdlib>
using namespace std;
int random(int start,int end)//产生一个(start,end)之间的随机整数
{
return start+rand()%(end-start+1);//rand()产生一个随机整数
}
int qSortOne(vector<int> &p,int left,int right)//随机划分一次(一次快排划分)
{
int i=(int)(random(left,right));
int a=p[left];
p[left]=p[i];
p[i]=a;
a=p[left];
while(left<right)
{
while(a<p[right])
{
right--;
}
p[left]=p[right];
p[right]=a;
while(a>p[left])
{
left++;
}
p[right]=p[left];
p[left]=a;
}
return left;
}
void findK(vector<int> &w,int left,int right,int k)
{
if(left<=right)
{
int start=qSortOne(w,left,right);
if(start>k)//只递归一边
{
findK(w,left,start-1,k);
}
else if(start<k)
{
findK(w,start+1,right,k);
}
else
{
cout<<"the number data["<<k<<"] is: "<<w[start]<<endl;
}
}
}
int main()
{
vector<int> a;
int temp;
int k;
cout<<"please input k!"<<endl;
cin>>k;
cout<<"please input array a[],end by ctrl+z!"<<endl;
while(cin>>temp)
{
a.push_back(temp);
}
findK(a,0,a.size()-1,k);
for(int i=0;i<a.size();i++)
{
cout<<a[i]<<"\t";
}
}
b.寻找第k小元素(选择划分基准线性时间选择)
#include<iostream>
#include<vector>
#include<cstdlib>
#include<algorithm>
using namespace std;
int random(int start,int end)
{
return start+rand()%(end-start+1);
}
//比较元素已然确定,就不需要再在函数内部选了
int Partition(vector<int> &d,int left,int right,int k)
{
int i = left-1,j = right + 1;
while(true)
{
while(d[++i]<k&&i<right);
while(d[--j]>k);
if(i>=j)
{
break;
}
swap(d[i],d[j]);
}
return j;
}
//冒泡排序,用于对小组内元素排序
void Bubble(vector<int> &d,int left,int right)
{
bool exchange;
for(int i=0;i<=right-left;i++)
{
exchange=false;
for(int j=left;j<right-i;j++)
{
if(d[j]>d[j+1])
{
swap(d[j],d[j+1]);
exchange=true;
}
}
if(!exchange)
{
return;
}
}
}
int Select(vector<int> &d,int left,int right,int k)
{
if(left-right<75)//如果排序个数小于75个,就直接排序,返回第k大小的元素值
{
Bubble(d,left,right);
return d[left+k-1];
}
int i;
//如果排序个数大于75个,再用找中位数的中位数的方法来减少运算次数
for(i=0;i<=(right-left-4)/5;i++)
{
Bubble(d,left+i*5,left+i*5+4);//各小组内部排序
swap(d[left+i*5+2],d[left+i]);//将各小组的中位数都移到数组最左端
}
i--;
if((left+i*5+4)<right)//处理最后一小组,组员不足5个的情况
{
Bubble(d,left+i*5+4+1,right);
swap(d[(right-(left+i*5+4))/2],d[left+i+1]);
}
int dx=Select(d,left,left+(right-left-4)/5,(right-left-4)/(2*5));//找中位数的中位数的值
int Nk=Partition(d,left,right,dx);//以中位数的中位数为界,分割数组,返回中位数位置
int num=Nk-left+1;//比中位数小的数的数量
if(num<=k)
{
return Select(d,left,Nk,k);//如果k小于等于num,在中位数的中位数的左边找
}
else
{
return Select(d,Nk+1,right,k-num);
}
}
int main()
{
vector<int> data;
int n;
cout<<"please input the size of array data[]!"<<endl;
cin>>n;
for(int i=0;i<n;i++)
{
data.push_back(random(0,500));
}
int k;
cout<<"please input the k you want!"<<endl;
cin>>k;
cout<<"the number is: "<<Select(data,0,n-1,k)<<endl;
for(int i=0;i<data.size();i++)
{
cout<<"data["<<i+1<<"]: "<<data[i]<<"\t";
}
cout<<endl;
}
8.最接近点对问题
a.O(n^2)暴力法
#include<iostream>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef struct Node
{
int x;
int y;
};
vector<Node> d;
int random(int s,int e)
{
return s+rand()%(e-s+1);
}
double dis(int a,int b)
{
return sqrt(pow(d[b].x-d[a].x+0.0,2)+pow(d[b].y-d[a].y+0.0,2));
}
bool cmpxy(Node a,Node b)
{
if(a.x!=b.x)
{
return a.x<b.x;
}
return a.y<b.y;
}
bool cmpy(int a,int b)
{
return a<b;
}
double Count(int left,int right)
{
vector<int> temt;
if(left+1==right)//只有两个元素,直接返回
{
return dis(right,left);
}
else if(left+2==right)//只有三个元素,按中位数分后,有一边只有一个元素,所以也是直接计算,返回结果
{
double d1=dis(right,left);
double d2=dis(right,left+1);
double d3=dis(right-1,left);
return min(min(d1,d2),d3);
}
double d1=Count(left,(left+right)/2);//以x坐标排序中位线划分左区
double d2=Count((left+right)/2+1,right);//以x坐标排序中位线划分右区
double dx=min(d1,d2);
for(int i=left;i<=right;i++)//没有按《算法设计与分析》中描写一样,这里是直接用暴力,将整个[-dx,dx]区间的数给囊括了
{
if(fabs(d[(left+right)/2].x-d[i].x)<dx)
{
temt.push_back(i);
}
}
sort(temt.begin(),temt.end(),cmpy);//在区间囊括的数,按y值,进行排序
for(int i=0;i<temt.size();i++)
{
for(int j=i+1;j<temt.size()&&d[temt[j]].y-d[temt[i]].y<dx;j++)
{
double d3=dis(temt[i],temt[j]);//囊括在区间的数,也不分是SL的还是SR的,凡是纵坐标之差小于dx的,全部暴力求解dis
if(dx>d3) //所以这个算法的复杂度是O(n^2),而不是算法设计与分析》中的n*logn
{
dx=d3;
}
}
}
return dx;
}
int main()
{
int num;
cin>>num;
Node temp;
for(int i=0;i<num;i++)
{
temp.x=random(0,200);
temp.y=random(0,200);
d.push_back(temp);
cout<<temp.x<<" "<<temp.y<<endl;
}
sort(d.begin(),d.end(),cmpxy);//没有使用线性时间查找中位数的方法,而是直接排序求各级的中位数了
cout<<Count(0,num-1)<<endl;
}