信息学奥赛一本通 2077:【21CSPJ普及组】小熊的果篮(fruit) | 洛谷 P7912 [CSP-J 2021] 小熊的果篮

本文主要是介绍信息学奥赛一本通 2077:【21CSPJ普及组】小熊的果篮(fruit) | 洛谷 P7912 [CSP-J 2021] 小熊的果篮,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【题目链接】

信息学奥赛一本通 2077:【21CSPJ普及组】小熊的果篮(fruit)
洛谷 P7912 [CSP-J 2021] 小熊的果篮

【题目考点】

1. 链表
2. stl list
3. stl set

【解题思路】

解法1:链表中包含链表

创建一个block双向链表,block链表中的每个元素都是一个“块”。
(之所以建双向链表,是因为下面有在block链表中删除结点的操作,双向链表删除写起来相对比较容易。如果使用单链表也可以完成该题。)
每个“块”也是一个单向链表,叫做fruit链表,保存这一个块中每个水果的编号。
首先根据读入的序列,创建block链表。

  • 如果当前读入数字(水果编号)和上个数字相同,则把当前数字加到当前fruit链表之中。
  • 否则在block链表中用尾插法添加一个元素(fruit链表),新的fruit链表添加水果编号

每次遍历block链表,在block链表中的每个“块”中(fruit链表)取第一个数字输出,并删除fruit链表中的第一个数字。
如果当前fruit链表在删除数字后,成为空链表,那么需要在block链表中删除该空链表,并判断前一个链表和后一个链表的水果种类是否相同,如果相同,则合并两个单链表(即把后一个链表接到前一个链表的后面)。

针对该解法可以自己写链表,也可以使用STL list类来完成。

解法2:使用两个set

set的原理是红黑树,可以维护一个有序序列,可以使用lower_bound或upper_bound成员函数以 O ( l o g n ) O(logn) O(logn)复杂度找到其中符合某一条件的元素。
设两个set:st0与st1。st0:保存种类为0的水果的编号 st1:保存种类为1的水果的编号
每次循环,从st0与st1哪个集合的最小值更小,就从哪个集合开始。交替在st0与st1中选择数字,下一次在另一个集合中选择出的数字要比上一次选择出的数字更大,并删除数字。直到在另一个集合中选择出的数字没有比上一次选择出的数字更大,则跳出循环。

由于set使用lower_bound的复杂度是 O ( l o g n ) O(logn) O(logn),该过程需要做n次,总体复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),是可以接受的。

【题解代码】

解法1:链表中包含链表
  • 写法1:自己写链表
#include <bits/stdc++.h>
using namespace std;
#define N 200005
struct Fruit//fruit链表中结点类型 
{int num;//num:水果编号 int next;//单链表下一个结点的地址 
};
Fruit fruit[2*N];//由于有头结点,总结点数多于N 
int fp, ft;
int TEST;
struct Block//block链表中结点类型 
{int type, head, tail;//type:水果种类  head:头指针 tail:尾指针 int pre, next;//pre, next:双向链表中前一个结点及下一个结点的地址int front(){return fruit[fruit[head].next].num;}void push_back(int num){fruit[++fp].num = num;fruit[tail].next = fp;tail = fp;}void pop_front(){head = fruit[head].next;}bool empty(){return head == tail;}void merge(Block bk)//当前链表末尾连接新链表 新链表为bk {fruit[tail].next = fruit[bk.head].next;tail = bk.tail;} 
};
Block block[N];
int bp, bhead = ++bp, btail = bhead;
void block_push_back(int type, int fruitNum)//type:水果类型 fruitNum:第一个水果编号 
{block[++bp].type = type;block[bp].head = block[bp].tail = ++fp;//在添加结点时,才给该block内的fruit链表设头结点 block[bp].push_back(fruitNum);block[bp].pre = btail;block[btail].next = bp;btail = bp;
}
bool block_empty()
{return bhead == btail;
}
void block_erase(int ep)//删掉地址为ep的结点 
{block[block[ep].pre].next = block[ep].next;block[block[ep].next].pre = block[ep].pre;if(btail == ep)btail = block[ep].pre;
}
int main()
{int n, a, lastNum = -1;//ln:上一次读入的数 cin >> n;for(int i = 1; i <= n; ++i){cin >> a; if(a == lastNum)block[btail].push_back(i);else{block_push_back(a, i);lastNum = a;}}while(block_empty() == false)//block链表不空 {for(int i = block[bhead].next; i != 0; i = block[i].next){//取出每块第一个水果,并删除水果的Fruit结点 cout << block[i].front() << ' ';block[i].pop_front();}cout << endl;for(int i = block[bhead].next; i != 0; i = block[i].next)//删除没有水果的块 if(block[i].empty())block_erase(i);int i = block[bhead].next;while(block[i].next != 0)//合并块i,nx{ int nx = block[i].next;if(block[i].type == block[nx].type){block[i].merge(block[nx]);block_erase(nx);}elsei = block[i].next;}}return 0;
}
  • 写法2:使用stl list
#include <bits/stdc++.h>
using namespace std;
#define N 200005
typedef list<list<int> >::iterator BlockIt;
typedef list<int>::iterator It;
list<list<int> > block;
int f[N];//f[i]:第i个水果是什么 
int main()
{int n, a, lastNum = -1;//ln:上一次读入的数 cin >> n;for(int i = 1; i <= n; ++i){cin >> a;f[i] = a;if(a == lastNum)prev(block.end())->push_back(i);//block最后元素添加i else{list<int> fruit;fruit.push_back(i);block.push_back(fruit);lastNum = a;}}while(block.empty() == false){BlockIt bi; for(bi = block.begin(); bi != block.end(); ++bi){//输出头 cout << bi->front() << ' ';bi->pop_front();}cout << endl;bi = block.begin();while(bi != block.end()){//删除 if(bi->empty())bi = block.erase(bi);//删掉bi指向的结点,并让bi指向下一个结点 else++bi;}bi = block.begin(); while(next(bi) != block.end()){BlockIt pi = bi++;//pi在前,bi在后,判断pi,bi指向的结点是否可以合并 if(f[*pi->begin()] == f[*bi->begin()]){//类型相同, 可以合并 pi->splice(pi->end(), *bi);block.erase(bi);bi = pi;}}}return 0;
} 
解法2:使用两个set
#include <bits/stdc++.h>
using namespace std;
#define N 200005
set<int> st[2];//st[0]:保存种类为0的水果的编号 st[1]:保存种类为1的水果的编号 
int main()
{int n, a, p, lastNum; cin >> n;for(int i = 1; i <= n; ++i){cin >> a;if(a == 0)st[0].insert(i);elsest[1].insert(i);}while(!(st[0].empty() && st[1].empty())){if(st[0].empty())//确定p中起始下标位置 p = 1;else if(st[1].empty())p = 0;else if(*st[0].begin() > *st[1].begin())p = 1;elsep = 0;lastNum = -1;while(true){set<int>::iterator it = st[p].lower_bound(lastNum); if(it == st[p].end())break;cout << *it << ' ';lastNum = *it;st[p].erase(it);p = (p+1)%2;//p从0变为1,1变为0; }cout << endl; }return 0;
} 

这篇关于信息学奥赛一本通 2077:【21CSPJ普及组】小熊的果篮(fruit) | 洛谷 P7912 [CSP-J 2021] 小熊的果篮的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/178520

相关文章

数据结构:二叉树详解 c++信息学奥赛基础知识讲解

目录 一、二叉树的定义 二、二叉树的形态 三、二叉树的性质 四、二叉树的存储 五、二叉树的创建与遍历(递归) 六、二叉树实现 创建二叉树 展示二叉树 1、计算数的高度 2、计算数的叶子数量 3、计算数的宽度 4、层次遍历 5、前序遍历 递归写法 非递归写法 6、中序遍历 递归写法 非递归写法 7、后序遍历 递归写法 非递归写法 8、输出根节点到所有叶

2021-02-16物料档案条码添加和蓝牙条码标签打印,金蝶安卓盘点机PDA,金蝶仓库条码管理WMS系统

物料档案条码添加和蓝牙条码标签打印,金蝶安卓盘点机PDA https://member.bilibili.com/platform/upload-manager/article 本期视频我们来讲解一下汉点机PDA条码添加和条码标签蓝牙便携打印: 在实际使用中,我们商品有两种情况: 一种是商品本身就有条码, 比如:超市卖的可口可乐,牛奶等商品,商品本身就有69开头的国标码,那么我们就可以使用盘点

2024全国各地高考录取分数线一览表(含一本、二本、专科)

2024年高考录取分数线陆续公布,上大学网(www.sdaxue.com)为大家整理全国31个省市高考录取分数线汇总,包括本科批、专科批和特殊类招生控制分数线汇总,来看看你的省份多少分能上大学吧。 一、2024年全国高考录取线一览表 1、宁夏 一本线:文科496分、理科432分; 二本线:文科419分、理科371分; 专科线:文理科均为200分。 2、云南 一本线:文科550分、

洛谷 P10584 [蓝桥杯 2024 国 A] 数学题(整除分块+杜教筛)

题目 思路来源 登录 - Luogu Spilopelia 题解 参考了两篇洛谷题解,第一篇能得出这个式子,第二篇有比较严格的复杂度分析 结合去年蓝桥杯洛谷P9238,基本就能得出这题的正确做法 代码 #include<bits/stdc++.h>#include<iostream>#include<cstdio>#include<map>#include<uno

2024.06.23【读书笔记】丨生物信息学与功能基因组学(第十七章 人类基因组 第四部分)【AI测试版】

第四部分:人类基因组的伦理、法律和社会问题(ELSI) 摘要: 本部分探讨了人类基因组计划所引发的伦理、法律和社会问题(ELSI),这些问题涉及基因信息的所有权、隐私权、基因歧视以及基因技术在社会中的运用等方面。 学习目标: 理解人类基因组计划实施过程中所引发的ELSI问题。掌握基因信息的伦理学考量,包括隐私保护和数据共享。学习基因技术在医疗、法律和社会层面的应用及其带来的挑战。 正文

第13关:存储过程1、第14关:存储过程2。(2021数据库期末一)

目录 首先需要学习和了解的知识 第13关:存储过程1 任务描述 答案  第14关:存储过程2 任务描述 答案 本篇博客的答案博主是学习别人得来的,敢于借鉴和学习哈哈!! 首先需要学习和了解的知识 了解什么是存储过程以及存储过程的基本语法。(作者博客专栏或者b站学习)了解在命令行中,执行创建存储过程的SQL时。需要通过关键字 delimiter 指定SQL语句的结束

洛谷P8502题解

[problem] \color{blue}{\texttt{[problem]}} [problem] [Solution] \color{blue}{\texttt{[Solution]}} [Solution] 这题最恶心的地方是卡空间。 我们先考虑不卡空间时怎么做。 直接并不好做,我们考虑正难则反,即利用容斥原理。答案应为从 a a a 没有任何限制经过 m m m 条

洛谷:P1085 [NOIP2004 普及组] 不高兴的津津

1. 题目链接 https://www.luogu.com.cn/problem/P1085 P1085 [NOIP2004 普及组] 不高兴的津津 2. 题目描述 题目描述:津津每天要上课还要上辅导班,每天学习超过8小时就不开心,帮忙检查下津津的下周日程安排,然后告诉我她哪天不高兴 输入:7行数据,每行2个小于10的非负整数,分别代表在学校的时间和辅导班的时间 输出:哪天最不高兴,如果有

【洛谷P3366】【模板】最小生成树 解题报告

洛谷P3366 -【模板】最小生成树 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz。 输入格式 第一行包含两个整数 N , M N,M N,M,表示该图共有 N N N 个结点和 M M M 条无向边。 接下来 M M M 行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi​,Yi​,Zi​,表示有一条长度为 Z

洛谷:P5714 【深基3.例7】肥胖问题

1. 题目链接 https://www.luogu.com.cn/problem/P5714 P5714 【深基3.例7】肥胖问题 2. 题目描述 题目描述:BMI计算:m / (h * h),m是体重(kg),h是身高(m) 小于18.5:体重国轻,Underweight 小于等于18.5且小于24:正常,Normal 大于等于24:肥胖,不仅要输出BMI值,换行,输出Overweigh