NEUQ-ACM预备队-week3-线性数据结构

P3613 寄包柜

题目

在这里插入图片描述

难点

原本以为:寄包柜这个输入输出非常复杂,数据蛮大的题是四道题中最难的一道,放在了最后做,但是很快理解了这道题:实际上是要创建一个很大的二维数组,存放寄包柜与格子,可是,用二维数组很明显无法开辟这么大的空间,因此需要用可变数组–vector来实现,这样,我们只需要创建一个嵌套容器,并使用resize函数重设vector的大小即可解决问题。

代码实现

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int n,q;
	cin >> n >> q;
	vector<vector<int> >a(n + 1);
	
	while (q--)
	{
		int x, i, j, k;
		cin >> x>>i>>j;
		
		if (x == 1)
		{
			
			cin  >> k;
			//如果寄包柜不够大 那么就利用resize()函数重设寄包柜
			if (a[i].size() < j + 1)
			{
				a[i].resize(j + 1);
			}
			a[i][j] = k;			
		}
		else if (x == 2)
		{
			
			cout << a[i][j] << endl;
		}
	}
	return 0;
}

P1449 后缀表达式

题目

在这里插入图片描述

解题思路

  1. 利用栈存储以 ‘ . ’ 字符间隔的数字
  2. 检索四则运算的符号,进行四则运算

难点分析

  1. 从一个字符串中取出数字存放在栈中,这有点类似与高精度数的存储,因为个位十位百位,所以不同的位数我们需要乘以不同的十的幂次,这一点比较难以实现,并且需要检索两个‘ . ’之间的数字序列,也需要合理的设置循环

代码实现

#include<iostream>
#include<stack>
#include<string>
#include<algorithm>
#include<cstdio>
using namespace std;
int main()
{
	stack<int>stack;
	string str;
	cin >> str;
	for (int i = 0; str[i] != '@'; i++)
	{
		int num = 0;
		int beishu = 1;
		//书写if时,我们需要考虑清楚:if的条件应该有几个,也就是str[i]会出现几种情况
		//1、str[i]=='.'
		//2、str[i] >= '0' && str[i] <= '9'
		//3、str[i]是四则运算符之一
		//因此,我们需要考虑清楚这三种情况中,if应该执行的语句
		//1、出现.时,应该将两个点之间的字符串型数字转为整型数字压入栈
		//2、出现数字时,不理会
		//3、出现四则运算时,设计四则运算
		if (str[i] == '.')
		{
			for (int j = i - 1; str[j] >= '0' && str[j] <= '9'; j--)
			{
				//借此保留一下位数 用倍数的逐增记录
				num += (str[j] - 48) * beishu;
				beishu *= 10;
			}
			stack.push(num);
		}
		else if (str[i] >= '0' && str[i] <= '9')continue;
		else
		{
			//根据后缀表达式,取且仅取栈顶的两个元素作为操作数
			//先利用一个k存储栈顶元素并令这个栈顶元素出栈
			int k = stack.top();
			stack.pop();
			//同时使用ans存储这次操作后的结果 并在最后将ans压入栈
			int ans = 0;
			if (str[i] == '+')
			{
				ans = k + stack.top();
				stack.pop();
			}
			else if (str[i] == '-')
			{
				//根据先进后出原则,栈顶取出的元素即k应该是减数与除数
				//后续取出的元素应该是被减数与被除数
				ans = stack.top()-k;
				stack.pop();
			}
			else if (str[i] == '/')
			{
				ans = stack.top() /k;
				stack.pop();
			}
			else if(str[i]=='*')
			{
				ans = k * stack.top();
				stack.pop();
			}
			stack.push(ans);
		}
	}
	cout << stack.top() << endl;
	return 0;
}

难点解决

int num = 0;
		int beishu = 1;
		if (str[i] == '.')
		{
			for (int j = i - 1; str[j] >= '0' && str[j] <= '9'; j--)
			{
				//借此保留一下位数 用倍数的逐增记录
				num += (str[j] - 48) * beishu;
				beishu *= 10;
			}
			stack.push(num);
		}

我们在累计压入栈的数字时,可以记录一个倍数,由于是从右向左检索字符串,也即先查找个位数,再查找十位数,那么,我们所累计的乘数–倍数,就应该从1开始逐个乘十,借此来正确的表达数位。

P1241 括号序列

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

解题思路

  1. 设置一个结构体,写入一个sic来保存是否这个括号是否被配对
  2. 遍历全部的括号,写入sic的情况(配对后写入1,未配对写入0)
  3. 遵照sic,设置不同的输出情况

代码实现

#include<iostream>
using namespace std;
struct kuohao {
	char a;
	int sic=0;
};
int main()
{
	struct kuohao arr[105];
	int len = 0;
	arr[len].a = getchar();
	arr[len].sic = 0;
	while (arr[len].a != '\n')
	{
		len++;
		arr[len].a = getchar();
		arr[len].sic = 0;
	}
	//从左到右依次遍历全部的括号序列
	for (int i = 0; i <= len; i++)
	{
		//找到右括号后,就开始从右括号的左边寻找到第一个左括号,并且,无论
		//是否能够正确配对,都要结束寻找左括号,我们只找最近的那个未配对左括号
		if (arr[i].a == ')' || arr[i].a == ']')
		{
			for (int j = i - 1; j >= 0; j--)
			{
				if ((arr[j].a == '(' || arr[j].a == '[')&&arr[j].sic!=1)
				{
					if (arr[j].a == '(' && arr[i].a == ')')
					{
						arr[j].sic = 1;
						arr[i].sic = 1;
						break;
					}
					else if (arr[j].a == '[' && arr[i].a == ']')
					{
						arr[j].sic = 1;
						arr[i].sic = 1;
						break;
					}
					else break;
				}	
			}
		}
	}
	//检验并输出
	for (int i = 0; i <= len; i++)
	{
		if (arr[i].sic == 1)
		{
			cout << arr[i].a;
		}
		else
		{
			if (arr[i].a == '(' || arr[i].a == ')')
				cout << "()";
			else if (arr[i].a == '[' || arr[i].a == ']')
				cout << "[]";
		}
	}
	return 0;
}

P1160 队列安排

题目

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

解题思路

QAQ,解题思路完全遵照祝神给的markdown文件照抄所以orz润一下解题思路

代码实现

#include<iostream>
#include<vector>
using namespace std;
const int mx = 1e5 + 10;
struct student {
	int l, r;
	int d;
}stu[mx]={0};
//i表示第几号同学,k表示i要插入的同学,p是i要插入k的左边还是右边的标志
void add(int i, int k, int p)
{
	//p=0,表明要插在k号同学的左手边,那么,i同学的右手将拉k同学的左手,i同学的左手将拉k同学左手拉的同学
	//如此一来,k同学右手拉的同学的右手应该拉i同学的左手
	//同时,k同学的左手应该拉i同学
	if (p == 0)
	{
		stu[i].r = k;
		stu[i].l = stu[k].l;
		stu[stu[i].l].r = i;
		stu[k].l = i;
	}
	//如果插入k同学的右边 那么 i同学的左手拉k同学的右手
	//i同学的右手拉k同学右手拉的同学
	//同时,k同学原来右手边的同学,也就是i同学现在右手边的同学的左手应该拉i
	//且,k同学的右手应该拉i同学
	else
	{
		stu[i].l = k;
		stu[i].r = stu[k].r;
		stu[stu[i].r].l = i;
		stu[k].r = i;
	}
}
//x是要删除的同学
void del(int x)
{
	stu[x].d = 1;
}
int main()
{
	int n = 0; cin >> n;
	add(1, 0, 1);
	for (int i = 2; i <= n; i++)
	{
		int k, p;
		cin >> k >> p;
		add(i, k, p);
	}
	int m; cin >> m;
	while (m--)
	{
		int x; cin >> x;
		del(x);
	}
	for (int i = stu[0].r; i; i = stu[i].r)
	{
		if (stu[i].d != 1)
			cout << i<<" ";
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值