8.29算法(dp,动态规划,打表

 最少货币数

//dp表记录当前价格所需的最小钱数
// 每种情况下有几种选择
// 只有满足条件才能选
// 打表从小到大打
// 
//
const int n = 10;
int select[n],dp[n];
int fdp(int m) {
	if (dp[m]) { return dp[m]; }
	for (int i = 1; i <= n; i++) {
		//之前理解的i是范围,即选择的范围
		//这样的理解是片面,虽然在一定程度上可以说明问题
		//但i还得是选择,用“选择”来解释更能说明问题
		//i=1即选择第一种,i=2即选择第二种的情况
		//那么max就是在不同的选择中择出最大值
		if (m >= select[i]) {
			dp[m] = max(dp[m], fdp(m-select[i]) + 1);
		}
	}
	return dp[m];
}
//可以选择通过调用函数,递归调用,只填表填可能出现的值
	//也可以在函数中让i从1遍历到总钱数,把表全打完,再直接返回总钱数的dp,
	//

 最多字符串解读数

//dp表记录当前长度的最多编码可能数
//之后每增加一位都是在现在的基础上的
//遇到特殊数字也可能把前面的一些情况舍去了
//
// 首先是要遍历串,保证能够编译,之后才能放心大胆
// dp[i]表示前i位数字共能组成的情况,第i位上无关,即往后顺延了一位
// 要看新加的这一位数字,加要算上前一位,算上前一位,处于11-19,21-26,则有两种翻译方法
// 如果看成两位数,即在原来有i-2位的基础上加了这么一个二位数,原来没加的时候情况不必
// 那么dp[i]=dp[i-2],
// 看成两个一位数,那么就是在有i-1位的基础上加了第i位这么一个数,原来i-1位有多少情况,现在就有多少种
//即dp[i]=dp[i-1];
//如果新加数字和前一位数构不成歧义,即加上后解读只有一种情况
//那依然保持原有的解读数
// 只不过内容可能不一样
//可能前面是1,之前读只有一种情况为a,现在加上0,现在读也就只有一种情况,为g
//尽管解读出的内容变了,但是解读无歧义,没有别的解读方法,依然不会增加解读数,只是内容变了
func() {
	if(num=){}
	for (int i = 1; i <= nums.size(); i++) {
		if (nums[i] == '0') {
			if (nums[i - 1] != '1' && nums[i - 2] != '2') {
				return 0;
			}
		}
	}
	for (int i = 2; i <= nums.size(); i++) {
		if ((nums[i - 2] == '1' && nums[i - 1] != '0') || (nums[i - 2] == '2' && nums[i - 1] < '7')) {
			dp[i] = dp[i - 1] + dp[i - 2];
		}//前两位数解读有歧义
		//剩余的都是没歧义的情况,和前面的解读数保持一致,尽管内容不同
		else { dp[i] = dp[i - 1]; }
	}
}

 最长子串,连续,序列

//如果说是连续的
//dp数组记录s1从i开始,s2从j开始的最长
fdp() {
	if (s1[i] == s2[j]) {
		dp[i][j] = dp[i - 1][j - 1] + 1;
	}//如果相同,就在前面的基础上继续增加
	else {//如果不同,就说明连续的终结,需要重新计数
		dp[i][j] = 0;
	}//如果是序列,则是视情况,保留原有基础,或换一种别的子串保留
}

 

//子串不一定从头开始
// 
//创建了一个二维容器,横是第一个字符串长度,列是第二个字符串
// dp[i][j]表示第一个字符串到第i位,第二个到第j位,形成的两个字串的最长公共长度
// 那么i,j越往后越大,所以打表顺寻为从左往右
// i,同时增一位,如果增的字符相同,则新格子的dp来自左上角的dp+1
// 如果不相同,即第一个字符串向下增的字符和第二个字符串向右增的字符不同
// 首先要确定,即是增的不同,新格子的值至少也是左上角的格子的值,只会增不会降
// 然后比较新格子的左方和上方的dp,
// 如果左方dp大,就意味第一个字符串向下增的字符在之前的第二个字符串(即第二个串没有增字符)里能找到
// 而且可以加入到最新后缀,那么此时第二个串再加一个字符,
// 由于之前没加的时候和第一个字符串已经有了一个匹配值,现在加了,字符串1也加了
// 但不相同,就说明第二个字符串加的字符没用,对新格子的dp值没有影响
// 而新格子是同时加了两个字符,所以取那个有用的,即字符串1加的字符
// 因为字符串1加的字符能在原有的字符2里找到,而且能产生影响,所以会在原来左上的格子基础上+1
// 又字符1不动时,字符2加的字符没用,所以新格子在两字符同时加的情况下,取加的有用的那个,即左方和上方的最大值
// 可能新加的字符都是无用的,那就保留左上的dp值
// 可能分开是无用的,但新加的相同,就成有用的,即左上和左,上相同,新格子比它们都大
//先控制每个行字符,依次挪动列字符,直到相等
if (s1[i] == s2[j]) { dp[i][j] = dp[i - 1][j - 1] + 1; }
else {
	dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
//打表是升序的,只会升高不会降低,即dp[i-1][j],dp[i][j-1]>=dp[i-1][j-1]
// dp[i-1][j]意味着在原来的基础上s2加了一个字符
// dp[i][j-1]意味s1加了一个字符,如果dp比原来高了,就说明这个新加的字符参与构成了子串
// 打表自左上开始往右下打,递推找值时自新点往左上找,不会往别的方向找
// 左上方向的极限就是左壁和右壁,即s1全部和s2第一个字符或s2全部,s1一个字符
//如果要翻译出这个字符串,就需要记录那些字符是有用的
//即哪些字符在加入的时候使dp提升了,哪些字符就参与构成了子串
//如果我要确定一个点的dp,那我就需要知道这个点左,上,左上的dp值
else {
if (dp[i - 1][j] > dp[i][j - 1]) {//s1增的字符有用,在左上的基础上加了个1,
	//向下增的字符有用,则总能往左方找到与之相同的新增字符
	//如果是第一个,那就说明原来新增的无用字符,在这次匹配上了
	//不然,就说明一直加了很多没用的,只是dp值一直保留的最近的加的有用的时候
	//即保持了加的有用的值的基础,而不断加了很多没用的,依然能找dp值这么多的最长序列
	//当左和上相等且都比左上大时,就说明s1,s2新加的字符对各自都是有用的
	//那么就说明此时出现了多解,在记录时可以统一一个方向
	//用b二维数组来记录当前这个点是来自于左上的哪个方向
	//由于是公共字符,所以里面的字符是都有的
	//在不相等时,会出现都有用和都没用的情况
	// 都有用,则两个格子都比左上大,且相等,都没用,则上面三个格子一样大,
	// 如果不相等的情况下,右下比左上相比还大了,就说明换情况了,最长的已经不是之前dp记录下的那个子串了
	//相等时也会,则下面三个格子相等,都没用上面三个格子相同
	//在原来的基础上,新加的相等,是在原来的基础上的,即还是保持在原来的子串上进行加
	//如果不相等还加了,那就只能说明换情况了,是在都有用的两个情况里选择的一种
	//左上比左,上小时,在左,上选择一种,实际上就是在换最长子串
	//只有左上和新格子dp值相同,才说明保持了原有的方案,不然要么是新加的字符相同才保留了原有方案
	//要么是在来自左,上的新方案中选择了一个新的,即抛弃了原来保留的旧的最长方案
	//新方案,来自于说新加的字符有用,而新的字符有没有用是和那个方向格子上的左上比,
	//当新加字符相同时,实际上来自左上,左,上都可以,此时哪个方向上都是有用的
	//但是代表的实际字符串不一定相同,每个方向都代表不同的字符串
	//新方案,同样来自于添加相同的字符,只不过原有的字符基础不一样,对应生成的最长字符也不一样
	// 采取新方案而不来自左上角,就是保留的最长字符串的转移,新方案的最长同样来自于相同字符的添加
	// 但实际上,只要没有相同字符的添加,现有的最长字符串长度就不会变,只不过是不同情况的转移
	//那么,只有在遇到左上时才会加字符,其他情况
	dp[i][j]=dp[i-1]
}
}
if (i == 0 || j == 0) { return res; }
if (b[i][j] == 1) { res += ans(i - 1, j - 1, b); //来自左上,加
res += x[i - 1];
else if (b[i][j] == 2) { res += ans(i - 1, j, b); }
else if()
}
else if(b[i][j])

最短矩阵和

 

//dp用来记录到达当前位置的最小和
//打表顺序为从上到下
int dr[2] = { 1,0 }, dc[2] = { 0,1 };
fdp() {
	if (dp[i][j]) { return dp[i][j]; }
	if (i == 1 && j == 1) { dp[i][j] = 1; return dp[i][j]; }
	for (int k = 0; k <= 1; k++) {
		int oldr = dr[k] + i, oldc = dc[k] + j;
		if (newr >= ) {
			dp[i][j] = min(dp[i][j], dp[newr][newc] + map[i][j];)
		}
	}

}
//或者dp记录从当前位置到终点的最小和
//打表的顺序,总是从表中数值较小打向较大的,无论递归怎么写的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值