IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【新初二暑假集训第一期day1晚间测试】题解 -> 正文阅读

[数据结构与算法]【新初二暑假集训第一期day1晚间测试】题解

话说发的是不是晚了点

T1 性格公交车(bus.cpp)

考点:队列+栈

首先,我们都会想到写一个包含 n u m num num s u m sum sum 的结构体,在完成输入后,按照如下方式排列:

bool cmp(node a,node b){
	return a.sum<b.sum;
}

具体含义不用赘述,排完之后,就会得到按照座位长度升序排序的座位号。

所以和队列跟栈有什么关系?

当然有!首先用一个队列把排序后的座位号塞进去。(此时,队列里的座位号都是空的

接下来,处理各种人。

  1. 处理内向的人

内向的人总是选择两个座位都是空的一排。在这些空座位排当中,选择一排座位宽度最小的,并占了其中的一个座位

前面我们所定义的队列里的每一个座位号都是空的,而队首座位号对应的座位的长度是最短的

所以,我们需要输出队首的座位号,并将其压入栈(此时,栈里的座位号都只坐了 1 个人),再删掉。

  1. 处理外向的人

外向的人总是选择一个内向的人所占的那排座位。在这些座位排当中,选择一排座位宽度最大的,并在其中占据了空位。

我们分别从两段加黑文字中,得到两个信息:

  1. 外向的人的座位号必须在栈里面找(栈里的座位号都只坐了 1 个人)
  2. 外向的人的座位是栈顶【排序过后,先压入栈内的对应的座位的长度是较短的,后压入栈内的对应的座位的长度是较长的)的座位号

应该写的算清楚,都懂?

处理了外向的人之后,将栈顶座位号弹出即可。

T2 表达式求值

考点:

这不比这道简单百倍?

首先,处理输入。

输入方式应该是有多种,这里我采用了如下输入方式:

while(1){
	scanf("%lld%c",&n,&ch);//分别输入数字和字符
}

由于只求最后四位,所以进行预处理,即对 n n n 取模 10000 10000 10000

接下来,考虑符号:

  1. ch 是加号

我们直接将 n n n 压入栈中,不做处理。

  1. ch 是乘号

弹出栈顶元素,与 n n n 相乘,再压入栈中(注意取模)。

  1. ch 是其他符号

输入结束了,跳出输入循环。

完成输入后,我们就处理了所有乘号,只剩下了加号。

换言之,我们只需要将栈里面的元素全部相加即可。(注意取模)

个人认为是水题一道,也是考试当天上午的重点讲解题目(没做起的建议回炉重造),不再赘述,下一题。

T3 题海战

考点:set

话说我的做法和GM做法不太一样?

2 2 2 ~ n + 1 n+1 n+1 行,先是 1 1 1 个正整数 p p p ,然后 p p p 个整数表示第 i i i 个学生的做题记录(可以重复做同一道题)。

从这段话中,我们可以得到两个信息:

  1. 做题顺序不一定是有序的
  2. 可能有重复做的题

所以,我们要做两个操作:排序和去重

养 set 千日,用 set 一时

首先,处理学生的题目。

考虑有多个学生,所以我们要定义一个 set 数组,即:

set<int> s[105];//set[i]表示第 i 个学生的完成的题目的升序排序后的结果

接下来,按照题目要求输入。(你不要告诉我你不会输入

然后,处理每一场比赛或训练应该准备的题目

  1. 比赛

准备一个 int 类型的 f l a g flag flag 数组,其中, f l a g [ ? i ? ] flag[\ i\ ] flag[?i?] 表示有 i i i要参加比赛的学生学生完成了第 i i i 题。

一个两重循环即可完成该任务(第 1 1 1 重循环枚举学生,第 2 2 2 重循环枚举当前学生所完成的题目)。

亲测,不用去重,不会超时。

对于每场比赛,他要保证所出的题没有任何一道已有任何一个学生做过

所以,再用 1 1 1 重循环枚举 f l a g flag flag ,当 f l a g [ ? i ? ] = 0 flag[\ i\ ]=0 flag[?i?]=0 时,输出当前的 i i i

我认为我应该讲清楚了

  1. 训练

前面的步奏和处理比赛一模一样,但最后一步有所不同。

而对于每场训练,他要保证所出的所有题都被每一个参赛学生做过

所以,用 1 1 1 重循环枚举 f l a g flag flag ,当 f l a g [ ? i ? ] = q flag[\ i\ ]=q flag[?i?]=q(参赛学生数)时,输出当前的 i i i

这题就完成了?

注意:这里有个大坑点!!!

每行的第1个整数type表示是训练或者比赛(1为训练,非1为比赛)

所以,我们应该写成:

if(type==1){
	训练代码
}else{
	比赛代码
}

而不是:

if(type==0){
	比赛代码
}else{
	训练代码
}

相信大家都应该看得出来。下一题。

T4 四色地图

考点:DFS

输入有些麻烦,结合代码:

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d ",&m);			//处理第 m 个区域
		char ch;
		while(1){			//由于我们不知道第 m 个区域与多少个区域相连,所以使用无限循环
			scanf("%d%c",&x,&ch);			//输入数字以及其后面的字符
			len[m]++;			//与第 m 个区域相邻的区域的数量增加
			a[m][len[m]]=x;			//记录
			if(ch!=' '){			//如果 ch 不是空格,说明已经换行了,跳出循环,进行第 m+1 个区域的输入
				break;
			}
		}
	}
	dfs(1);			//开始搜索
	return 0;
}

关于搜索,方法很多。以下仅代表个人观点。

我们可以定义一个 f l a g flag flag 二维数组。

其中: f l a g [ ? i ? ] [ ? j ? ] flag[\ i\ ][\ j\ ] flag[?i?][?j?] 表示第 i i i 个区域是否可以涂 j j j 号颜色。

对于每一个区域 i i i ,我们可以从 1 ~ 4 1\sim4 14 进行遍历,当 f l a g [ ? i ? ] [ ? j ? ] flag[\ i\ ][\ j\ ] flag[?i?][?j?] 0 0 0 时,说明我们可以选择该颜色进行填涂,那么我们将该颜色 j j j 存储在一个 a n s ans ans 数组里,并将所有与 i i i 区域相邻的 k k k 区域标记: f l a g [ ? k ? ] [ ? j ? ] = 1 flag[\ k\ ][\ j\ ]=1 flag[?k?][?j?]=1 (即第 k k k 个区域不能用颜色 j j j 填涂)

完成了这些处理之后,我们就可以进行下一步搜索了。

当搜索完成后,我们只需要输出 a n s ans ans 数组即可。

T5 潜水员

考点: 二维费用背包

这是一道变式二维背包,首先,回顾一下一般二维背包的状态定义以及状态转移方程。

定义状态:

d p [ ? i ? ] [ ? j ? ] [ ? k ? ] dp[\ i\ ][\ j\ ][\ k\ ] dp[?i?][?j?][?k?] 表示选择前 i i i 个物品,氧气最多为 j j j ,氮气最多为 k k k 时的最小重量。

对于第 i i i 个物品,我们都有选与不选两种状态,则我们容易得到状态转移方程:

d p [ ? i ? ] [ ? j ? ] [ ? k ? ] = min ? ( d p [ ? i ? 1 ? ] [ ? j ? ] [ ? k ? ] , d p [ ? i ? 1 ? ] [ ? j ? a [ ? i ? ] ? ] [ ? k ? b [ ? i ? ] ? ] + c [ ? i ? ] ) dp[\ i\ ][\ j\ ][\ k\ ]=\min(dp[\ i-1\ ][\ j\ ][\ k\ ],dp[\ i-1\ ][\ j-a[\ i\ ]\ ][\ k-b[\ i\ ]\ ]+c[\ i\ ]) dp[?i?][?j?][?k?]=min(dp[?i?1?][?j?][?k?],dp[?i?1?][?j?a[?i?]?][?k?b[?i?]?]+c[?i?])

当然,这个方程太复杂了,所以,我们可以降维打击,简化状态转移方程:

d p [ ? j ? ] [ ? k ? ] = min ? ( d p [ ? j ? ] [ ? k ? ] , d p [ ? j ? a [ ? i ? ] ? ] [ ? k ? b [ ? i ? ] ? ] + c [ ? i ? ] ) ( 1 ? i ? n ) dp[\ j\ ][\ k\ ]=\min(dp[\ j\ ][\ k\ ],dp[\ j-a[\ i\ ]\ ][\ k-b[\ i\ ]\ ]+c[\ i\ ])(1\leqslant i \leqslant n) dp[?j?][?k?]=min(dp[?j?][?k?],dp[?j?a[?i?]?][?k?b[?i?]?]+c[?i?])(1?i?n)

注意初始化:

d p [ ? j ? ] [ ? k ? ] = { 0 j = 0 , k = 0 2 31 ? 1 j ≠ 0 , k ≠ 0 dp[\ j\ ][\ k\ ]=\begin{cases}0&j=0,k=0\\2^{31}-1&j\neq0,k\neq0\end{cases} dp[?j?][?k?]={0231?1?j=0,k=0j?=0,k?=0?

但是!

如果不能恰好带这么多气体,允许多带一些(先考虑氧气最小,再考虑氮气最小)。

所以,我们在进行循环跑 DP 时,就需要用一些小技巧:

for(int i=1;i<=n;i++){			//n 个物品
	for(int j=u+100;j>=a[i];j--){			//因为可以允许多带一些气体,所以我们应该从 u+一些数 开始跑循环
											//而题目已知 ai 和 bi 都在区间 [1,100] 以内,所以,我们就应该从 u+100 开始跑循环
		for(int k=v+100;k>=b[i];k--){			//同上
			dp[j][k]=min(dp[j][k],dp[j-a[i]][k-b[i]]+c[i]);
		}
	}
}

但是,因为我们进行了特殊的处理,所以答案不应该在 d p [ ? u ? ] [ ? v ? ] dp[\ u\ ][\ v\ ] dp[?u?][?v?] 中。

for(int i=u;i<=u+100;i++){			//因为可以多带,所以要进行循环枚举
	for(int j=v;j<=v+100;j++){
		if(dp[i][j]!=0x3f3f3f3f){			//该情况是有解的
			printf("%d",dp[i][j]);			//直接输出,因为题目要求先考虑氧气最小,再考虑氮气最小
				return 0;
		}
	}
}
printf("-1");			//无解

那么这题也就完成了。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 19:09:52  更:2022-07-20 19:13:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:13:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码