Map映射模拟队列(南昌理工学院ACM集训队)

倖福魔咒の 提交于 2021-01-18 14:22:35

Map映射模拟队列(南昌理工学院ACM集训队)

Map是由key到value组成的映射,每一个key对应一个唯一的value,因此在数据量非常大的时候能用Map映射快速检索到相应的元素。

①Map包含在头文件#include<map>
②定义map<key,value>name;
key为被映射的数据类型,value表示key映射到的数据类型,map的key和value可以是int、long long、struct 等等任意的数据类型,name为映射的名字

因为Map可以直接快速搜索到key对应的value,所以当数据非常大的时候我们可以用Map模拟队列用BFS的方式解决问题

例题

洛谷U129453 「EZEC-4.5」占座位

题目描述

图书馆内有 nnn 个座位围成一个圈,编号依次为 1∼n,若干人依次进入图书馆占座位。

但是他们不想与他人靠得太近,因此他们占座位有 3个原则:

①第一个人选择 1号座位。

②设 d(x) 为 x 号座位与其旁边最近的人之间的空座位数(即不包括这两个座位)。 从第二个人开始,每个人都会坐在使 d(x) 最大的座位 x 上,若有多个座位满足条件,坐在编号最小的座位上。

③若没有任何空座位 x 满足 d(x)≥k ,则无法再坐人。

例 若n = 7,k = 1

因为这是一个圆桌,每一个人去坐都会尽量使周围两边的空位最多,所以相当于每个人都会把剩余空位尽量分成两半,因此可以用二叉树来模拟。

         7
		  |
	      6
	     / \
	    2   3
		   / \
		  1   1

例 若 n = 17 , k = 2

         17
	     | 
	     16
	    /   \
	   7     8
      / \   / \
     3   3 3   4
     

每个节点的权值代表剩余的空位,每个节点向下延伸的时候都-1,代表去掉自己的位置剩余的空位,一直到权值无法大于等于2为止

剩下的部分就是检索总共有多少个有子节点的节点,然后将结果输出就行

定义一个map

map<long long,long long>jd;

第一个long long代表节点的权值
第二个long long代表相应权值的数量
例如有三个权值为5的结点,则jd[5]=3;

接下来按照bfs的思路,将第一个map映射进入循环,若可以分出子节点则将子节点输入队列,如果队列里已经有与子节点权值相同的映射则将其加上父节点的权值,然后将原节点删除,最后判断map是否为空,若为空则结束循环

rbegin() 指向容器的最后一个元素
rbegin()->first 为最后一个元素的key

if (!jd.empty()) {
   
   
			n = jd.rbegin()->first;//返回map中最后一个元素的key(相当于队列中的front())
		}

同理 rbegin()->second 为最后一个元素的value

下面是代码部分


#include<iostream>
#include<map>
using namespace std;
#define ll long long
ll k, ans = 0;
map<ll, ll>jd;//定义一个map映射,所代表的是结点的权值和权值为这个数的数量
void bfs(ll n) {
   
   
	while (!jd.empty()) {
   
   //当map为空时退出循环
		if (n % 2 == 0) {
   
   
			if (n / 2 > 2 * k) {
   
   
				if (jd[n / 2])   jd[n / 2] += jd[n];
				else   jd[n / 2] = jd[n];//map中没有key代表的映射,则创建一个新的映射
				ans += jd[n];
			}
			if (n / 2 - 1 > 2 * k) {
   
   
				if (jd[n / 2 - 1])   jd[n / 2 - 1] += jd[n];
				else   jd[n / 2 - 1] = jd[n];
				ans += jd[n];
			}
		}
		else if (n % 2 != 0 && (n - 1) / 2 > 2 * k) {
   
   
			if (jd[(n - 1) / 2])   jd[(n - 1) / 2] += jd[n] * 2;
			else   jd[(n - 1) / 2] = jd[n] * 2;
			ans += jd[n] * 2;
		}
		jd.erase(n);//清除n代表的映射,类似队列中的pop
		if (!jd.empty()) {
   
   
			n = jd.rbegin()->first;
		}
	}
}
int main()
{
   
   
	ll n;
	cin >> n >> k;
	jd[n-1] = 1;//一开始1号位坐了第一个人,剩余空位为n-1
	bfs(n-1);
	cout << ans + 2 << endl;//最后结果加上一开始减去的两个人就是最后的答案
}

蒟蒻代码码风比较乱看懂就好QAQ

下面是官方题解与思路(膜拜大佬)
U129453 「EZEC-4.5」占座位-君のNOIP。 的博客

当然题目可能还有其他的做法,毕竟大犇千千万,蒟蒻我一人 ~o( =∩ω∩= )m

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!