左神算法学习日记——递归和动态规划

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<xfunctional>
#include<sstream>
#include<memory>
#include<numeric>
using namespace std;

//汉诺塔问题,将汉诺塔问题分为子问题,每个子问题都用同一种方式对待,最后底层栈会逐次返回子问题的答案
void process(int n, wstring from, wstring to, wstring help)
{
	if (n == 1)
		wcout << L"move 1 from " + from + L" to " + to<<endl;//在主函数中设置locale::global(locale("chs")),这样可以使得一次读取两个字节,直接用string也可以
	else
	{
		process(n - 1, from, help, to);//将n-1个圆盘借助to从from移到help
		wcout << L"move " + to_wstring(n) + L" from " + from + L" to " + to<<endl;//把最大那个移到to
		process(n - 1, help, to, from);//将n-1个圆盘借助from从help移到to
	}
}
//输出所有子串
void printAllsub(int i,string s,string cur)
{
	if (i == s.size())
	{
		cout << cur << endl;
		return;
	}
    //按照字符串中字符的顺序依次决策是否选择该子串,直到最后一个字符输出当前的子串
	printAllsub(i + 1, s, cur);
	printAllsub(i + 1, s, cur + s[i]);
}
//输出所有子序列
void substr(int i, int pre,string s, string cur)
{
	if (i == s.size())
	{
		cout << cur << endl;
		return;
	}
	substr(i + 1,pre, s, cur);
	if ((i-pre)<2||pre==-1)//在子串递归的基础上出去不连续的子串
		substr(i + 1, i, s, cur + s[i]);
}
//输出所有全排列
void printAllPer(int i,string cur)
{
	if (i == cur.size())//在字符位置超出限制后输出当前获得的排列
	{
		cout << cur<<endl;
		return;
	}
    将全排列问题转化为字符串交换顺序问题
	for (int j = i; j < cur.size(); j++)
	{
		swap(cur[i], cur[j]);//决策和哪一个字符交换
		printAllPer(i + 1, cur);//下一个字符和哪个进行交换
	}//在第一个位置和每个位置都进行过交换后活动的所有全排列
}
//一头母牛每年可以生一头母牛,母牛三岁后可以生牛,且牛永远不会死掉,问i年后有多少母牛
int printniu(int i)
{
	if (i <= 4)
		return i;//第一年牛有1头,第二年牛有两头,第三年牛有三头,第四年牛有四头
	return printniu(i - 1) + printniu(i - 3);//第五年的时候第二年的牛可以生牛了,所以再加上第二年的牛所生的牛
}

int minDis(vector<vector<int>> &mat,int r, int c)
{
	if (r == mat.size()-1 || c == mat[0].size()-1)
		return mat[r][c];//当到达右下角结点时,返回当前距离
	if (r == mat.size()-1)
		return mat[r][c] + minDis(mat, r, c + 1);
	if (c == mat.size()-1)
		return mat[r][c] + minDis(mat, r + 1, c);//当走到最下边和最右边的时候,只有一条路可以走
	return mat[r][c] + min(minDis(mat, r + 1, c), minDis(mat, r, c + 1));//每走一步都要决策选哪一边走距离较近,递归中每一个位置有信息都一样,存在复用现象,可以将这种递归转化为动态规划问题
}

bool ishave1(vector<int> &arr, int cur,int sum,int aim)
{
	if (cur == arr.size())
		return sum==aim;
	return ishave(arr, cur + 1, sum + arr[cur], aim) || ishave(arr, cur + 1, sum, aim);//数组中是否含有和为sum的子数组,该递归也存在复用现象
}

bool ishave2(vector<int> arr, int aim)
{
	int s = accumulate(arr.begin(), arr.end(),0);
	vector<vector<int>> dp(arr.size()+1,vector<int>(s+1,0));//建立一个纵坐标为数组和,横坐标为当前数在数组中的位置
	dp[arr.size()][aim] = 1;//和不是aim与和不存在的位置都是false,只有和为aim的位置为true
	for (int i = arr.size(); i > 0; i--)
	{
		for (int j = 0; j < s + 1; j++)
		{
			dp[i][j] = dp[i + 1][j] || dp[i + 1][j+arr[j]];//当前数不算入子数组时的和是否是aim,当前数算入子数组时的和是否是aim
		}
	}
	return dp[0][0];
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值