ACM实训-递归递推(递归实现+DFS+优化搜索)

目录

A (1). 猴子摘桃 (递归)

B (2). 移梵塔 (hanno递归实现)

C (3). 九连环(递归模拟)

D (4). 2的幂次方(递归+STL)

E (5). 攀天梯(Fibonacci递归实现+记忆化搜索)

F (6). 递归函数(递归)

G (7). 滑雪(记忆化搜索优化DFS)

H (8). 马拦过河卒(双向搜索优化DFS)

I (9). 乐乐的棋盘(DFS)《oj数据出错,未判》

J (10). 数的计数(DFS)

K (11). 骑士游历问题(递归,记忆化搜索)

L (12). 分式(递归模拟)

M (13). 兔子繁殖(详细题解:传送门)(Fibonacci,高精度)

N (14). 帕斯卡的旅行(线性DP)

O (15). 棋子移动(递推,string)

P (16). Hanoi双塔问题(Hanno,高精度)


题解不易,点个赞再走吧

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;
}

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

panjyash

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值