目录
E (5). 攀天梯(Fibonacci递归实现+记忆化搜索)
M (13). 兔子繁殖(详细题解:传送门)(Fibonacci,高精度)
题解不易,点个赞再走吧
A (1). 猴子摘桃 (递归)
#include<bits/stdc++.h>
using namespace std;
int f(int n) {
//递归
return (n==1)?2:(f(n-1)+1)*2;
/*可化简为:
if(n==1)
return 2;
else
return (f(n-1)+1)*2;
*/
//递推
/*
int t=2;
for(int i=2;i<=n;i++)
t=(t+1)*2;
return t;
*/
}
int main() {
int n;
cin>>n;
cout<<f(n);
return 0;
}
B (2). 移梵塔 (hanno递归实现)
//分析:
/*
有题我们可以把Hanno塔三个柱分别看作起始柱
、辅助柱、目标柱。借助递归来改变A,B,C的性质
*/
#include<bits/stdc++.h>
using namespace std;
int t,n;
void hanno(int n,char ch1,char ch2,char ch3) {
if(n==1) {
printf("%c-%d-%c\n",ch1,n,ch3);
return ;
}//当n==1时,由A->C;
hanno(n-1,ch1,ch3,ch2);
printf("%c-%d-%c\n",ch1,n,ch3);
hanno(n-1,ch2,ch1,ch3);
}
int main() {
t=1;
char ch1='A',ch2='B',ch3='C';
while(t--) {
cin>>n;
hanno(n,ch1,ch2,ch3);
}
return 0;
}
C (3). 九连环(递归模拟)
//分析:
/*
递归实现的过程中,我们可以把总问题看作多个子问题
即保证1 ~ x-2为0,x-1为1,从而使x变为0
*/
#include<bits/stdc++.h>
using namespace std;
int a[21]= {1,1,1,1,1,1,1,1,1,1};
int n;
void f(int x) {
if(n==0)
return;
//保证每层x-1位置的数为1,当此处为0时,就进行一次转化
if(!a[x-1])
f(x-1);
//保证1~x-2位置的数为0,当此处为1时就进行一次转化
for(int i=x-2; i>=1; i--)
if(a[i])
f(i);
if(n==0)
return;
n--;//对操作数迭减
a[x]=1-a[x];//转换0~1,1~0
}
int main() {
cin>>n;
for(int i=9; i>=1; i--)
if(a[i])
f(i);
//逆序处理
if(n)
return printf("-1");
for(int i=1; i<=9; i++)
cout<<a[i];
return 0;
}
D (4). 2的幂次方(递归+STL<string>)
//分析:
/*
就本质来说该题是多个2或者2(0)结合
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
string f(ll x) {
return x==1?"2(0)":"2";
}//提供子段
int ff(ll x) {
ll cnt=0;
while(x>>=1)
cnt++;
return cnt;
}//求x对应2进制的最高位
string fff(ll x) {
ll t=x&-x,cnt=0;
string s;
while(x) {
s=(t<=2)?f(t)+(s.empty()?"":"+")+s:"2("+fff(ff(t))+")"+(s.empty()?"":"+")+s;
x^=t;
t=x&-x;
}
return s;
}//递归处理
int main() {
cin>>n;
cout<<fff(n);
return 0;
}
E (5). 攀天梯(Fibonacci递归实现+记忆化搜索)
//分析:
/*
Fibonacci数列,在借助递归处理问题时,会有大量的重复子问题
其性质
当n==0||n==1时 f(n)=1;
否则 f(n)=f(n-1)+f(n-2);
如5--f(5)
=f(4)+f(3)
=(f(3)+f(2))+f(3) f(3)出现一次重复
=(f(2)+f(1)+f(2))+f(2)+f(1) f(2),f(1)均出现重复
=(f(1)+f(0)+f(1)+f(1)+f(0))+f(1)+f(0)+f(1)
由上可见递归处理时出现多个重复子问题
因此需要记忆化搜索优化问题
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll a[81];
ll f(ll n) {
if(a[n])
return a[n];//记忆化
return a[n]=(n<=1?1:f(n-1)+f(n-2));
}
int main() {
cin>>n;
cout<<f(n);
return 0;
}
F (6). 递归函数(递归)
//递归处理
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 25;
ll a,b,c;
ll f[N][N][N];
ll w(ll a, ll b, ll c) {
if(a<=0 || b<=0 || c<=0) return 1;
else if(a>20 || b>20 || c>20) return w(20, 20, 20);
else {
if(f[a][b][c]) return f[a][b][c];
if(a<b && b<c) f[a][b][c] = w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else f[a][b][c] = w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
return f[a][b][c];
}
}
int main() {
while(cin >> a >> b >> c&&(~a||~b||~c))
cout << w(a, b, c) << "\n";
return 0;
}
G (7). 滑雪(记忆化搜索优化DFS)
#include<bits/stdc++.h>
using namespace std;
int h[101][101],f[101][101];
int r,c;
int dir[4][2]= {0,1,1,0,0,-1,-1,0};//移动
bool judge(int x,int y,int xx,int yy) {
return xx<=0||yy<=0||h[x][y]<=h[xx][yy];
}//越界判断
int Dfs(int x,int y) {
if(f[x][y])
return f[x][y];//记忆化
for(int i=0; i<4; i++) {
int cx=x+dir[i][0],cy=y+dir[i][1];
if(judge(x,y,cx,cy))
continue;
f[x][y]=max(f[x][y],Dfs(cx,cy)+1);//递归
}
return f[x][y];
}
int main() {
cin>>r>>c;
for(int i=1; i<=r; i++)
for(int j=1; j<=c; j++)
cin>>h[i][j];
int mx=0;
for(int i=1; i<=r; i++)
for(int j=1; j<=r; j++)
mx=max(mx,Dfs(i,j)+1);
cout<<mx;
return 0;
}
H (8). 马拦过河卒(双向搜索优化DFS)
详细题解可点击进入:传送门
// 请使用本地IDE(如DEV-CPP)运行无误后再将代码粘贴至此处并提交!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define fi first
#define se second
PII b,c;
ll f[21][21],n,cnt;
bool vis[21][21];
int dir[9][2]={0,0,1,2,2,1,-1,2,2,-1,-2,1,1,-2,-1,-2,-2,-1};
void init(){
for(int i=0;i<9;i++){
int x=c.fi+dir[i][0],y=c.se+dir[i][1];
if(x>=0&&x<=b.fi&&y>=0&&y<=b.se)
vis[x][y]=true;
}
}
bool judge(int x,int y){
return (x>=0&&y>=0&&x<=b.fi&&y<=b.se&&!vis[x][y]);
}
void dfspre(int x,int y){
if(x+y==n+1){
f[x][y]++;
return;
}
if(judge(x+1,y))
dfspre(x+1,y);
if(judge(x,y+1))
dfspre(x,y+1);
}
void dfspost(int x,int y){
if(x+y==n+1){
cnt+=f[x][y];
return;
}
if(judge(x-1,y))
dfspost(x-1,y);
if(judge(x,y-1))
dfspost(x,y-1);
}
int main()
{
cin>>b.fi>>b.se>>c.fi>>c.se;
n=(b.fi+b.se)/2;
init();
dfspre(0,0);
dfspost(b.fi,b.se);
cout<<cnt;
return 0;
}
I (9). 乐乐的棋盘(DFS)《oj数据出错,未判》
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[101][101];
long long cnt;
bool judge(int x,int y) {
return x>n||y>m||a[x][y]==1;
}
void Dfs(int x,int y) {
if(x==n&&y==m)
cnt++;
if(!judge(x+1,y))
Dfs(x+1,y);
if(!judge(x,y+1))
Dfs(x,y+1);
}
void solve() {
cnt=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin>>a[i][j];
Dfs(1,1);
cout<<cnt<<"\n";
}
int main() {
while(cin>>n>>m)
solve();
return 0;
}
J (10). 数的计数(DFS)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1001;
int n,ans=1;
void Dfs(int n) {
if(n==1)
return;
ans+=n/2;//当前可构成的数量n/2
for(int i=2; i<=n/2; i++)
Dfs(i);//从2到n/2依次递归
}
int main() {
cin>>n;
Dfs(n);
cout<<ans;
return 0;
}
K (11). 骑士游历问题(递归,记忆化搜索)
//分析:
/*
骑士只可以向右移动,所以骑士所处位置的左边就是之前的位置,路径数为之前所有可能位置路径数的总和,即a[x,y]=f(x-2,y-1)+f(x-2,y+1)+f(x-1,y-2)+f(x-1,y+2);
*/
#include<bits/stdc++.h>
using namespace std;
long long a[52][52];
int m,n,x,y,xx,yy;
bool vis[52][52];
long long f(int x,int y) {
if(vis[x][y]||x<=0||y<=0||x>n||y>m)
return 0;
if(a[x][y]>0)
return a[x][y];
a[x][y]=f(x-2,y-1)+f(x-2,y+1)+f(x-1,y-2)+f(x-1,y+2);
if(a[x][y]==0ll)
vis[x][y]=true;//标记为0的位置,为0不进行下一次递归
return a[x][y];
}
int main() {
cin>>n>>m>>x>>y>>xx>>yy;
a[x][y]=1ll;
cout<<f(xx,yy);
return 0;
}
L (12). 分式(递归模拟)
//分析:
/*
每次反转a,b并对b+a
*/
#include<bits/stdc++.h>
using namespace std;
int n;
void f(int n,int a,int b){
if(n==1){
cout<<b<<"\n"<<a;
return;
}
f(n-1,b,a+b);
}
int main(){
cin>>n;
f(n,2,3);
return 0;
}
M (13). 兔子繁殖(详细题解:传送门)(Fibonacci,高精度)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e18;
struct int128 {
ll low,hig;
} a[101]= {{1,0},{1,0}};
int m,d;
int128 operator + (int128 a,int128 b) {
int128 t;
t.low=t.hig=0;
t.low=a.low+b.low;
t.hig=t.low/mod+a.hig+b.hig;
t.low%=mod;
return t;
}
void solve() {
a[0]=a[1]= {1,0};
d++;
for(int i=2; i<=d; i++) {
if(i<m)
a[i]=a[i-1]+a[0];
else
a[i]=a[i-1]+a[i-m];
}
if(a[d].hig)
cout<<a[d].hig;
cout<<a[d].low<<"\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
while(cin>>m>>d&&(m||d))
solve();
return 0;
}
N (14). 帕斯卡的旅行(线性DP)
#include<bits/stdc++.h>
using namespace std;
int n;
int a[50][50],f[50][50];
//f[i][j]表示(i,j)位置的路径数
//状态转移方程为:
/*
向右移动a[i][j]
f[i+a[i][j]][j]+=f[i][j]
向下移动a[i][j]
f[i][j+a[i][j]]+=f[i][j]
*/
int main() {
cin>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%1d",&a[i][j]);
f[1][1]=1;//对初始位置的赋值
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i+a[i][j]][j]+=f[i][j],//向右移动a[i][j]
f[i][j+a[i][j]]+=f[i][j];//向下移动a[i][j]
cout<<f[n][n];
return 0;
}
O (15). 棋子移动(递推,string)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string s="__";
int n,ans;
int main() {
cin>>n;
ans=(n-4)*2+5;
//step=(n-4)*2+5;
for(int i=0; i<n; i++)
s="*"+s;
for(int i=0; i<n; i++)
s="O"+s;
//构造字符串
while(n-->4) {
swap(s[n],s[(n+1)*2]);
swap(s[n+1],s[(n+1)*2+1]);
cout<<s<<"\n";
swap(s[n],s[n*2]);
swap(s[n+1],s[n*2+1]);
cout<<s<<"\n";
}//有普适性的进行递推
s=s.substr(10);
//最后几步没有普适性,直接抄的样例
cout<<"OOO__***O*"<<s<<"\n";
cout<<"OOO*O**__*"<<s<<"\n";
cout<<"O__*O**OO*"<<s<<"\n";
cout<<"O*O*O*__O*"<<s<<"\n";
cout<<"__O*O*O*O*"<<s<<"\n";
cout<<"step="<<ans;
return 0;
}
P (16). Hanoi双塔问题(Hanno,高精度)
//分析:
/*
对于Hanno塔的次数分析
1.将最上层几个移到另一个柱上,次数为a[i];
2.将最底层一个移到目标柱,次数为1,之后将1.移动的几个移到目标柱为a[i]
所以总次数为n-1层移动次数的两倍+1
即a[i]=a[i-1]*2+1;
之后借助这个原理来写高精度就可以了,一个很简单的高精乘低精
*/
#include<bits/stdc++.h>
using namespace std;
int n;
int a[200]={0,1},len=1;
void f(){
for(int i=1;i<=len;i++)
a[i]<<=1;
a[1]++;
for(int i=1;i<len;i++)
if(a[i]>=10){
a[i+1]+=a[i]/10;
a[i]%=10;
}
while(a[len]>=10){
a[len+1]=a[len]/10;
a[len]%=10;
len++;
}
}
int main()
{
cin>>n;
while(--n)
f();
for(int i=len;i>=1;i--)
a[i]<<=1;
for(int i=1;i<len;i++)
if(a[i]>=10){
a[i+1]+=a[i]/10;
a[i]%=10;
}
while(a[len]>=10){
a[len+1]=a[len]/10;
a[len]%=10;
len++;
}
for(int i=len;i>=1;i--)
cout<<a[i];
return 0;
}