ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

学堂在线-程序设计基础-第六章

2021-10-24 18:31:40  阅读:167  来源: 互联网

标签:binary partial int put 学堂 num 第六章 程序设计 best


文章目录

第六章 递推与动态规划

6.1 兔子数列问题

  先设定递推初值;再按照公式进行递推(常用循环实现)。

代码实现

//斐波那契数列 
#include <iostream>
using namespace std;

int main() 
{
	int n; 
	cout << "求第几个月的兔子个数: " ;
	cin >> n ;
	
	int dang_yue = 1;
	int shang_yue = 1;
	int qian_yue = 1;
	for (int i = 2; i < n; i ++)
	{
		dang_yue = qian_yue + shang_yue;
		qian_yue = shang_yue;
		shang_yue = dang_yue;
	} 
 
	cout << "第" << n << "个月的兔子总数为:" << dang_yue << endl; 
	return 0;
}

6.2 分鱼问题

6.2.2 从 A 到 E 递推-代码实现

//分鱼问题 
#include <iostream>
using namespace std;

int main() 
{
	int num[5]={0};
	for (num[0] = 1; ; num[0]++)
	{
		if (num[0] % 5 != 1)
			continue;
		int i;
		for (i = 1; i <= 4; i++)
		{
			num[i] = num[i-1] / 5 * 4;
			if (num[i] % 5 != 1)
				break;
		}
		if (i <= 4)
			continue;
		break;
	}
	for(int i = 0; i < 5; i++)
	cout << num[i] << " " << endl; 
	return 0;
}

6.2.3 从 E 到 A 递推-代码实现

  通过逻辑分析,优化枚举初值和枚举步长,提高代码运行效率

//分鱼问题 
#include <iostream>
using namespace std;

int main() 
{
	int num[5]={0};
	for (num[0] = 16; ; num[0]+=20)
	{
		int i;
		for (i = 0; i <4; i++)
		{
			if (num[i]%4!=0)
				break;
			num[i+1]=num[i]/4*5+1;
		}
		if (i <4)
			continue;
		break;
	}
	for(int i = 0; i < 5; i++)
	cout << num[i] << " " << endl; 
	return 0;
}

不用数组辅助-代码实现

  不用数组,反而没法用循环简化代码,不知道有没有其他更好的实现方式。

//分鱼问题 
#include <iostream>
using namespace std;

int main() 
{
	int num_a,num_b,num_c,num_d,num_e=0;
	for (num_e = 16; ; num_e+=20)
	{
		if (num_e%4!=0)
			continue;
		num_d=num_e/4*5+1;
		if (num_d%4!=0)
			continue;
		num_c=num_d/4*5+1;
		if (num_c%4!=0)
			continue;
		num_b=num_c/4*5+1;
		if (num_b%4!=0)
			continue;
		num_a=num_b/4*5+1;
		break;
	}
	cout << num_a << "\n" << num_b << "\n"
		 << num_c << "\n" << num_d << "\n"
		 << num_e << endl; 
	return 0;
}

6.3 橱窗的插画问题

  求最优值问题:

  • 首先用枚举法枚举出所有的情况,对于每个情况计算美感和并保存最大值;
  • 由于枚举法,每次计算中有许多重复计算,所以用一个数组存储一些部分插花方案的美感值,采用递归法计算,可以省去一部分计算,但是由于定义了一个数组,需要额外存储空间
  • 采用动态规划,计算并存储部分最优方案,极大优化了存储空间的占用

6.3.3 用枚举思想解题

//橱窗插花,用枚举思想解题
#include <iostream>
using namespace std;

const int V = 5, F = 3;
//把一个数num表示为二进制数组binary[]
void ToBinary(int num, int binary[V])
{
	for(int i = 0; i < V; i++)
	{
		binary[i] = num & 1;	//按位与,取最低为 
		num = num >> 1; 		//右移一位 
	}
} 
//计算binary中1的个数
int count1(int binary[V])
{
	int count = 0;
	for (int i = 0; i < V; i++)
		count += binary[i];
	return count;
} 

int main()
{	
	int beauty[V][F] = {{7  , 5  , -21},
						{23 , 21 , 5  },
						{-5 , -4 , -4 },
						{-24, 10 , -20},
						{16 , 23 , 20 }};//定义美感数组
	int best_beauty = 0, best_put = 0;//定义最大美感得分,和插花方案
	
	//枚举,从0到(2^V-1)
	for (int i = 0; i < (1<<V); i++)
	{
		int binary[V] = {0};
		ToBinary(i, binary);//得到插花方案binary[] 
		if (count1(binary) != F)//花的数量不对,枚举下一个方案
			continue;
		//计算美感得分
		int sum_beauty = 0;
		for (int vase = 0, flower = 0; vase < V; vase++)
			if (binary[vase] == 1)//该花瓶中插的有花
			{
				sum_beauty += beauty[vase][flower];
				flower++; 
			} 
		//保存最大美感和插花方案
		if (sum_beauty > best_beauty)
		{
			best_beauty = sum_beauty;
			best_put = i;
		} 
	} 

	//输出答案
	cout << "最大美感得分:" << best_beauty << endl;
	cout << "插花方案:";
	int best_binary[V] = {0};
	ToBinary(best_put, best_binary); 
	for (int vase = 0, flower = 1; vase < V; vase++)
	{
		if (best_binary[vase] == 1)
		{
			cout << flower;
			flower++;
		}
		else
			cout << 0;
	}
	return 0;
}

6.3.4 采用递归的优化算法

//橱窗插花,采用递归的优化算法 
#include <iostream>
using namespace std;

const int V = 5, F = 3;
//把一个数num表示为二进制数组binary[]
void ToBinary(int num, int binary[V])
{
	for(int i = 0; i < V; i++)
	{
		binary[i] = num & 1;	//按位与,取最低为 
		num = num >> 1; 		//右移一位 
	}
} 
//计算binary中1的个数
int count1(int binary[V], int &high)
{
	int count = 0;
	high = -1;
	for (int i = 0; i < V; i++)
		if (binary[i] == 1)
		{
			high = i;
			count++;
		}
	return count;
} 

int main()
{	
	int beauty[V][F] = {{7  , 5  , -21},
						{23 , 21 , 5  },
						{-5 , -4 , -4 },
						{-24, 10 , -20},
						{16 , 23 , 20 }};//定义美感数组
	int best_beauty = 0, best_put = 0;//定义最大美感得分,和插花方案
	
	int partial_sum[1<<V] = {0};
	//枚举,从0到(2^V-1)
	for (int i = 1; i < (1<<V); i++)
	{
		int binary[V] = {0};
		ToBinary(i, binary);
		int high;
		int flowers = count1(binary, high);
		if (flowers > F)//大于F非法方案,小于F局部方案,等于F完整插花方案 
			continue;
		partial_sum[i] = partial_sum[i-(1<<high)] + beauty[high][flowers-1];
		if (flowers == F && partial_sum[i] > best_beauty)
		{
			best_beauty = partial_sum[i];
			best_put = i;
		}	
	}

	//输出答案
	cout << "最大美感得分:" << best_beauty << endl;
	cout << "插花方案:";
	int best_binary[V] = {0};
	ToBinary(best_put, best_binary); 
	for (int vase = 0, flower = 1; vase < V; vase++)
	{
		if (best_binary[vase] == 1)
		{
			cout << flower;
			flower++;
		}
		else
			cout << 0;
	}
	return 0;
}

6.3.5.1 动态规划解题,输出方案1

//橱窗插花,动态规划,输出方案1 
#include <iostream>
using namespace std;

const int V = 5, F = 3;
//把一个数num表示为二进制数组binary[]
void ToBinary(int num, int binary[V])
{
	for(int i = 0; i < V; i++)
	{
		binary[i] = num & 1;	//按位与,取最低为 
		num = num >> 1; 		//右移一位 
	}
} 

int main()
{	
	int beauty[V][F] = {{7  , 5  , -21},
						{23 , 21 , 5  },
						{-5 , -4 , -4 },
						{-24, 10 , -20},
						{16 , 23 , 20 }};//定义美感数组
	
	int best_partial[V+1][F+1] = {{0}};
	int best_put[V+1][F+1] = {{0}};
	//m个花瓶插n朵花的局部最优解 
	for (int m = 1; m <= V; m++)
		for (int n = 1; n <= m && n <= F; n++)
		{
			best_partial[m][n] = best_partial[m-1][n-1] + beauty[m-1][n-1];
			best_put[m][n] = best_put[m-1][n-1] + (1<<(m-1));
			if (n < m && best_partial[m][n] < best_partial[m-1][n])
			{
				best_partial[m][n] = best_partial[m-1][n];
				best_put[m][n] = best_put[m-1][n];
			}
			cout << m << " "
				 << n << " "
				 << best_partial[m][n] << " "
				 << best_put[m][n] << endl;
		}
	

	//输出答案
	cout << "最大美感得分:" << best_partial[V][F] << endl;
	cout << "插花方案:";
	int best_binary[V] = {0};
	ToBinary(best_put[V][F], best_binary); 
	for (int vase = 0, flower = 1; vase < V; vase++)
	{
		if (best_binary[vase] == 1)
		{
			cout << flower;
			flower++;
		}
		else
			cout << 0;
	}
	return 0;
}

6.3.5.2 动态规划,输出方案2

  计算量和存储空间都得到优化,但输出为倒序

//橱窗插花,动态规划,输出方案2,回溯输出逆序 
#include <iostream>
using namespace std;

const int V = 5, F = 3;
//把一个数num表示为二进制数组binary[] 

int main()
{	
	int beauty[V][F] = {{7  , 5  , -21},
						{23 , 21 , 5  },
						{-5 , -4 , -4 },
						{-24, 10 , -20},
						{16 , 23 , 20 }};//定义美感数组
	
	int best_partial[V+1][F+1] = {{0}};
	bool best_put[V+1][F+1] = {{false}};
	//m个花瓶插n朵花的局部最优解 
	for (int m = 1; m <= V; m++)
		for (int n = 1; n <= m && n <= F; n++)
		{
			best_partial[m][n] = best_partial[m-1][n-1] + beauty[m-1][n-1];
			best_put[m][n] = true;
			if (n < m && best_partial[m][n] < best_partial[m-1][n])
			{
				best_partial[m][n] = best_partial[m-1][n];
				best_put[m][n] = false;
			}
			cout << m << " "
				 << n << " "
				 << best_partial[m][n] << " "
				 << best_put[m][n] << endl;
		}
	

	//输出答案
	cout << "最大美感得分:" << best_partial[V][F] << endl;
	cout << "插花方案:";
	for (int m = V, n = F; m > 0; )
	{
		if (best_put[m][n])
		{
			cout << n;
			m--;
			n--;
		}
		else
		{
			cout << '0';
			m--;
		}
	}
	return 0;
}

6.3.5.3 动态规划,输出方案2,正序输出

  思路是从第3朵花开始从第5个花瓶开始逆向插花:
  所有的循环和递归方式不变,只是计算时将美感数组beauty[][]转置;
  同样在输出时注意,逆序输出则第一个输出的是第1朵花;
在这里插入图片描述

//橱窗插花,动态规划,方案2,正序输出 
#include <iostream>
using namespace std;

const int V = 5, F = 3;

int main()
{	
	int beauty[V][F] = {{7  , 5  , -21},
						{23 , 21 , 5  },
						{-5 , -4 , -4 },
						{-24, 10 , -20},
						{16 , 23 , 20 }};//定义美感数组
	
	int best_partial[V+1][F+1] = {{0}};
	bool best_put[V+1][F+1] = {{false}};
	//m个花瓶插n朵花的局部最优解 
	for (int m = 1; m <= V; m++)
		for (int n = 1; n <= m && n <= F; n++)
		{
			best_partial[m][n] = best_partial[m-1][n-1] + beauty[V-m][F-n];
			best_put[m][n] = true;
			if (n < m && best_partial[m][n] < best_partial[m-1][n])
			{
				best_partial[m][n] = best_partial[m-1][n];
				best_put[m][n] = false;
			}
			cout << m << " "
				 << n << " "
				 << best_partial[m][n] << " "
				 << best_put[m][n] << endl;
		}
	

	//输出答案
	cout << "最大美感得分:" << best_partial[V][F] << endl;
	cout << "插花方案:";
	for (int m = V, n = F; m >= 1; )
		if (best_put[m][n] == true)
		{
			cout << F-n+1;
			m--;
			n--;
		}
		else
		{
			cout << 0;
			m--;
		}
	return 0;
}

6.4 最长公共子序列问题

  递归初始值的确定,需要仔细分析,本节课中的做法非常巧妙;
  存放长度的数组,可以用来进行比较,作为递归方向的判据;
  存放方向的数组,作为递归方向的标志,可以作为输出时回溯的判定;

//最长公共子序列问题 
#include <iostream>
#include <cstring>
using namespace std;

const int M = 10, N = 10;

int main() 
{
	char A[9] = "abcbdacb";		//要比较的字符串A 
	char B[6] = "bdcab";		//要比较的字符串B 
	int m = strlen(A);			//字符串A的长度作为循环范围 
	int n = strlen(B);			//字符串B的长度作为循环范围 
	int lcs[M][N];				//存放公共子序列的长度值 
	int decision[M][N];			//存放公共子序列计算时的取舍方向 
	enum		//定义取舍方向的标志 
	{
		I_J,	//i和j相等,子序列长度加1,lcs[i][j]=1+lsc[i+1][j+1] 
		I_1,	//i和j不相等,i+1比j公共子序列长度大,lsc[i][j]=lcs[i+1][j]
		J_1		//i和j不相等,j+1比i公共子序列长度大,lsc[i][j]=lcs[i][j+1] 
	};
	
	for (int i = 0; i < m+1; i++)
		lcs[i][n] = 0;	//初始化递归初值
	for (int j = 0; j < n+1; j++)
		lcs[m][j] = 0;	//初始化递归初值
	for (int i = m-1; i >= 0; i--)	//递归运算
		for (int j = n-1; j >= 0; j--)
			if ( A[i] == B[j])
			{
				lcs[i][j] = 1 + lcs[i+1][j+1];
				decision[i][j] = I_J;
			}
			else if ( lcs[i+1][j] > lcs[i][j+1])
			{
				lcs[i][j] = lcs[i+1][j];
				decision[i][j] = I_1;
			}
			else
			{
				lcs[i][j] = lcs[i][j+1];
				decision[i][j] = J_1;
			}
	
	for (int i = 0, j = 0; i < m && j < n; )	//回溯输出
		switch (decision[i][j])
		{
		case I_J:
			cout << A[i];
			i++;
			j++;
			break;
		case I_1:
			i++;
			break;
		case J_1:
			j++;
			break;
		}
	
	return 0;
}

语法自测-试题答案

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

标签:binary,partial,int,put,学堂,num,第六章,程序设计,best
来源: https://blog.csdn.net/u014238501/article/details/120471329

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有