递推递归是分治思想的体现,核心都是将问题分为结构相似的子问题。递推侧重于多米诺结构,递归侧重于包含结构。
对于递推,关键在于自下而上的找到多米诺骨牌上下者联系,进而写出递推方程。
P1.以洛谷P1002过河卒为例
分析子问题,从终点开始,附近点作为起点的条数是易知的,这是“下者”,对应某个上者,它的条数就是对应下者(右或下)的条数相加,即p[i,j]=p[i+1,j]+p[i,j+1]
#include<iostream>
using namespace std;
bool inthemap(int n,int m,int ntest,int mtest)
{
return ntest>=0&&ntest<=n&&mtest>=0&&mtest<=m;
}
struct mapspot
{
long long nums;
bool avail;
};
int main()
{
int n,m,horsen,horsem;
cin>>n>>m>>horsen>>horsem;
mapspot** mapp=new mapspot*[n+1];
for(int i=0;i<n+1;i++)
{
mapp[i]=new mapspot[m+1];
for(int j=0;j<m+1;j++)
{
mapp[i][j].avail=1;
mapp[i][j].nums=0;
}
}
mapp[n][m].nums=1;
int x[9]={-2,-2,-1,-1,0,1,1,2,2};
int y[9]={-1,1,-2,2,0,2,-2,1,-1};
for(int i=0;i<9;i++)
if(inthemap(n,m,horsen+y[i],horsem+x[i])) mapp[horsen+y[i]][horsem+x[i]].avail=0;
for(int i=n;i>=0;i--)//从底层到上层,为递推
{
for(int j=m;j>=0;j--)
{
if(inthemap(n,m,i+1,j)&&inthemap(n,m,i,j+1)) if(mapp[i][j].avail==1) mapp[i][j].nums=mapp[i+1][j].nums+mapp[i][j+1].nums;
if(!inthemap(n,m,i+1,j)&&inthemap(n,m,i,j+1)) if(mapp[i][j].avail==1) mapp[i][j].nums=mapp[i][j+1].nums;
if(inthemap(n,m,i+1,j)&&!inthemap(n,m,i,j+1)) if(mapp[i][j].avail==1) mapp[i][j].nums=mapp[i+1][j].nums;
}
}
cout<<mapp[0][0].nums<<endl;
return 0;
}
其中底层到上层的思路便是递推,上层到底层的分析便是递归。特别注意递归要注意return具体数值而非函数时的条件,此题中就是x(i,j)==0或i==n&&j==m.
而用递归的方式分析,当(i,j)不通即x(i,j)==0时,return 0;当(i,j)可以走时,f(i,j)将返回f(i+1,j)+f(i,j+1),递归的终点是i==n,j==m,return 1;
递推和递归,就是下推上和上推下的关系。