数据结构与算法MOOC-第二章线性表(多项式加法(map) 字符串插入 位查询 放苹果(递归orDP)大整数乘法)

  • 数据结构与算法Mooc-第二章线性表


  • 1、多项式加法

题目链接:1:多项式加法

思路:①看到需要合并同系数,排序果断选择用map容器,次数相同合并,那么Key值(First)肯定是选择次数

           ②输入是系数为负停止,那么第一次输入系数为负只需要continue,第二次结束输入(break)

           ③输入合法值时查找,如果找到对应次数,系数相加,找不到就插入该元素

代码:

#include	
#include
using namespace std;


int main()
{
	int Number, Pow;
	int Test_Time;
	cin >> Test_Time;
	while (Test_Time--)
	{
		map Polynomial;   //first-pow,second-Number
		int Break_Flag = 0;
		while (cin >> Number >> Pow)
		{
			if (Pow < 0)
			{
				Break_Flag++;
				if (Break_Flag== 1)  //到一表示第一组多项式输入完成
					continue;
				break;    //到2 两组都输入,结束输入
			}
			if (Polynomial.count(Pow)!=-1)     //find it
			{
				Polynomial[Pow] += Number;		//找到对应的次数,系数相加
				if (Polynomial[Pow]==0)		//系数为0
					Polynomial.erase(Pow);		//删除该子项
			}
			else
				Polynomial.insert(make_pair(Pow, Number));  //没有对应次数,加入该子项
		}

		if (Break_Flag == 2)
		{
			auto it = Polynomial.rbegin();
			for (it; it != Polynomial.rend(); it++)   //map默认升序,所以逆序输出
			{
				if (it == Polynomial.rbegin())
					cout << "[ " << it->second << " " << it->first << " ]";
				else
					cout << " [ " << it->second << " " << it->first << " ]";
			}
			cout << endl;
		}
	}
	return 0;
}

         收获:一个新的类型:auto,迭代器类,以后不用写长长的~<...>::iterator

         待解答:我自己写的系数相加,查找,插新一直WA,求解答,错误代码放下

while (Test_Time--)
{
	map Polynomial;   //first-pow,second-Number
	int Break_Flag = 0;
	while (cin >> Number >> Pow)
	{
		if (Pow < 0)
		{
			Break_Flag++;
			if (Break_Flag == 1)
				continue;
			break;
		}
		it = Polynomial.find(Pow);
		if (it != Polynomial.end())     //find it
		{
			it->second += Number;
			if (it->second == 0)
				Polynomial.erase(it->first);
		}
		else
			Polynomial.insert(pair(Pow, Number));
	}
  • 2、字符串插入

题目链接:2:字符串插入

思路:①在段极大ACSII码后插入字符串,找第一个最大码值,如果当前字符大于等于下一字符跳出就可以了

           ②把第一个最大码值后面的元素移动Len位,Len为插入字符串长度

           ②极端情况:最大值是最后一个,此时跳出查找部分的下标指向 '\0',需要把下标减一

代码:

#include
#include
using namespace std;
#define MAXLENGTH 100
//数据结构与算法mooc(第二章线性表2字符串插入)
int main()
{
	char str[MAXLENGTH], substr[MAXLENGTH];
	while (cin >> str >> substr)
	{
		int Len1 = strlen(str), Len2 = strlen(substr);
		int Index = 0;
		while (str[Index] != '\0')
		{
			if (str[Index] < str[Index+1])
				Index++;
			else
				break;
		}
		if (Index == Len1)
			Index--;
		if (Index != Len1 - 1)
		{
			for (int i = Len1 - 1; i > Index; i--)
				str[i + Len2] = str[i];
		}
		for (int i = 0; i < Len2; i++)
			str[i + Index + 1] = substr[i];
		str[Len1 + Len2] = '\0';

		cout << str << endl;
	}
	return 0;
}
  • 3、位查询

题目链接:3:位查询

必备基础:建议看看我写的一篇博,详细讲了位运算,还有对应的例题和应用:位运算总结 

#include
using namespace std;
#define MAXSIZE 100005
#define MAX 65535
//数据结构与算法mooc(第二章线性表3位查询)
int Bit_Check(int Number, int pow)
{
	Number >>= pow;		//右移i个位置
	return Number & 1;
}

int main()
{
	int Size, Op_Num;
	char Instruct;
	int Op_index;
	int Num[MAXSIZE];
	cin >> Size >> Op_Num;
	for (int i = 0; i < Size; i++)
		cin >> Num[i];
	
	while (Op_Num--)
	{
		int Statistic = 0;			//统计某二进制位为1的数量
		cin >> Instruct >> Op_index;
		if (Instruct == 'Q')
		{
			for (int i = 0; i < Size; i++)
				Bit_Check(Num[i], Op_index) == 1 ? Statistic++ : Statistic;   //该位是1,统计数目加一
			cout << Statistic << endl;
		}
		else
		{
			for (int i = 0; i < Size; i++)
			{
				Num[i] += Op_index;
				Num[i] = Num[i] > MAX ? Num[i] % (MAX + 1) : Num[i];
			}
		}
	}
	return 0;
}
  • 4、放苹果

题目链接:4:放苹果

思路(重点讲):将问题降维是解决递归和DP问题的通法,苹果数记为Apple_num,盘子数记为Plate_num

                     a.苹果数为1或盘子数为1:那么只有一种放法(前者一个苹果放在任一盘,后者全部苹果放一个盘)

                b.苹果数小于盘子数:那至少存在Plate_num-Apple_num个空盘子(假设每个盘子放一个苹果),问题等价于Apple_num个苹果放在Apple_num个盘子中,Carry_Apple(Apple_num,Plate_num)=Carry_Apple(Apple_num,Plate_num) ,因为就算每个盘子只放一个苹果最多也只能放Apple_num个盘子。

                     c.苹果数大于等于盘子数:分两种情况

                        ①每个盘子都有苹果:因为Apple>=Plate嘛,所以先取Plate_num个苹果使得每个盘子有一个苹果,剩余的苹果再进行放置,问题等价于Apple_num-Plate_num个苹果放在Plate_num个盘子Carry_Apple(Apple_num,Plate_num)=Carry_Apple(Apple_num-Plate_num,Plate_num)

                       ②至少有一个盘子没有苹果:去掉这些空的盘子,因为至少一个空嘛,那就先去掉一个空盘,问题等价于Apple_num个苹果放在Plate_num个盘子Carry_Apple(Apple_num,Plate_num)=Carry_Apple(Apple_num,Plate_num-1

 根据这两种情况,问题等价: 

Carry_Apple(Apple_num,Plate_num)=Carry_Apple(Apple_num-Plate_num,Plate_num)+Carry_Apple(Apple_num,Plate_num-1)

 

(1)递归实现代码

    注:递归实现的时候要考虑Apple_num=0的情况,因为当Apple_num-Plate_num有等于0的情况,由c,不难得出如果苹果数等于盘子数,第一种情况每个盘子都有苹果,那只有一种放法(每个盘子一个水果),第二种情况是不变的

问题等价:Carry_Apple(Apple_num,Plate_num)=1+Carry_Apple(Apple_num,Plate_num-1)

                  所以结束状态中添加苹果数等于0,有一种放法

int Carry_Apple(int Apple_num, int Plate_num)
{

	//苹果数量1或者0(考虑递归情况:Apple-Plate=0,那么每个盘子都要有苹果只有一种放置可能)
	//盘子数量1,那么所有苹果只能放在一个盘子,1种情况
	if (Apple_num == 1 || Apple_num == 0 || Plate_num == 1)
		return 1;

	//当苹果数量小于盘子树,那至少存在Plate-Apple个空盘,问题等价n个苹果放在n个盘子的情况
	else if (Apple_num < Plate_num)
		return Carry_Apple(Apple_num, Apple_num);

	//苹果数量大于盘子数,总的摆放方式由两种情况确定
	//1 每个盘子都有苹果:那么先取plate个苹果使得每个盘子都有一个苹果,问题等价于把剩余苹果分配给plate个盘子
	//2 存在没有苹果的盘子,问题等价于把Apple个苹果分给plate-1个盘子(至少有一个空盘)
	else				//Apple_num>=Plate_num
		return Carry_Apple(Apple_num - Plate_num, Plate_num) + Carry_Apple(Apple_num, Plate_num - 1);
}


int main()
{
	int Apple_num,Plate_num;
	int t;
	cin >> t;
	while (t--)
	{
		cin >> Apple_num >> Plate_num;
		cout << Carry_Apple(Apple_num, Plate_num) << endl;
	}
	return 0;
}

(2)DP实现代码

状态转移在上面写得很清楚了

注:DP从1开始,所以考虑需要独立出苹果数等于盘子数

此时:Carry_Apple(Apple_num,Plate_num)=1+Carry_Apple(Apple_num,Plate_num-1)

DP的题为了不超时,不重复计算,先提前打表

int Carry_Apple_DP[100][100] = { 0 };
int MAX_Time = 20;

void DP()
{
	for (int Apple = 1; Apple < MAX_Time; Apple++)
	{
		for (int Plate = 1; Plate < MAX_Time; Plate++)
		{
			if (Apple == 1 || Plate == 1)
				Carry_Apple_DP[Apple][Plate] = 1;
			else if (Apple < Plate)
				Carry_Apple_DP[Apple][Plate] = Carry_Apple_DP[Apple][Apple];
			else if (Apple == Plate)
				Carry_Apple_DP[Apple][Plate] = Carry_Apple_DP[Apple][Plate-1] + 1;   //plus,添加上这个的原因是Apple-Plate有可能是0,也就是Apple个苹果放Plate个盘子的情况(1),因为动态是从1开始!!!
			else  //Apple>=Plate
				Carry_Apple_DP[Apple][Plate] = Carry_Apple_DP[Apple - Plate][Plate] + Carry_Apple_DP[Apple][Plate - 1];
		}
	}
}

int main()
{
	DP();
	int Apple_num, Plate_num;
	int T;
	cin >> T;
	while(T--)
	{
		cin >> Apple_num >> Plate_num;
		cout << Carry_Apple_DP[Apple_num][Plate_num] << endl;
	}
}
  • 5、大整数乘法

问题链接:6:大整数乘法

思路:①模拟算术乘法,定一个数的位与另一个数所有位进行逐位相乘,直到定的数所有位遍历完

          ②逆序保存结果,0位是个位依次类推

实现代码:

#include
#include
using namespace std;
#define MAX_Length 1005
#define Decimal 10

int main()
{
	char Mutiply_Result[MAX_Length], Num_A[MAX_Length], Num_B[MAX_Length];
	
	for (int i = 0; i < MAX_Length; i++)    //结果字符串数组先初始化为字符0
		Mutiply_Result[i] = '0';
	cin >> Num_A >> Num_B;

	int Len_A = strlen(Num_A), Len_B = strlen(Num_B);

	if (Num_A[0] == '0' || Num_B[0] == '0')    //其中有一个乘数为0,直接输出0
	{
		cout << "0" << endl;
		return 1;
	}

	int Begin = 0, Index = 0, Carry_bit = 0;
	while (Len_B--)
	{
		int Temp_Len_A = Len_A;
		int Num;
		Index = Begin;
		Carry_bit = 0;     //进位
		while (Temp_Len_A--)
		{
			Num = (Num_B[Len_B] - '0')*(Num_A[Temp_Len_A] - '0') + Carry_bit;   
			if (Num >= Decimal)     //需要进位
			{
				Carry_bit = (Num - Num % Decimal) / Decimal;   //记录下一位的进位
				Num %= Decimal;    //Num为当前位的进位
			}
			else
				Carry_bit = 0;

			Mutiply_Result[Index] += Num;			//当前位加上当前位进位Num
			if (Mutiply_Result[Index] - '0' >= Decimal)   //当前位需要进位
			{
				Num = Mutiply_Result[Index] - '0';     //记录该位进制数值
				Mutiply_Result[Index + 1] += 1;			//下一位进1
				Mutiply_Result[Index] = Num % Decimal + '0';		//该位取余
			}

			Index++;    //进入下一位

			if (Carry_bit&&Temp_Len_A == 0)			//如果数A全部与数B的某一位乘完还存在进位,那么当前位的下一位(Index)得加上该进位
			{
				Mutiply_Result[Index] += Carry_bit;
				if (Len_B == 0)			//如果此时B所有位都完成乘法,那么当前位才是最高位,下一位才能结束
					Index++;
			}
		}
	

		Begin++;
	
	}

	
	Mutiply_Result[Index+1] = '\0';
	for (int i = Index-1 ; i >= 0; i--)
		cout << Mutiply_Result[i];
	cout << endl;
	return 0;
}

自己蠢的地方:要注意定位与另一个数逐位相乘的时候!!!高位是进位(因为结果是逆序的)

                         还有就是如果乘法上方数(小学乘法了解一下)与下方某位乘完,高位进位还不是0,那么得留下该进位

                         如果刚好是完成乘法啦,该进位保存之后,Index要记得+1,因为Index指向的是最高位,这时的最高位已经是下一位了。

if (Carry_bit&&Temp_Len_A == 0)			//如果数A全部与数B的某一位乘完还存在进位,那么当前位的下一位(Index)得加上该进位
			{
				Mutiply_Result[Index] += Carry_bit;
				if (Len_B == 0)			//如果此时B所有位都完成乘法,那么当前位才是最高位,下一位才能结束
					Index++;
			}

 

你可能感兴趣的:(算法与数据结构MOOC)