一.重复局面
这个题使用map会非常方便
直接上代码
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main(){
int n;
cin>>n;
string str,str2;
map<string,int>m;
for(int i=0;i<n;i++){
for(int j=0;j<8;j++){
cin>>str;
str2+=str;
}
m[str2]++;
cout<<m[str2]<<endl;
str2.clear();
}
return 0;
}
这个题用到了字符串拼接,和map<string,int>,并且注意1这里的str2要注意记得清空
本来这个题一开始我想的用二维字符数组或者一维string数组来作为map的键的,但是搜到了
所以想到了string可以进行比较可以作为键,map中的键也可以用结构体,所以对于这个题目来说,map中的键也可以使用结构体,里面放上8个string类型的变量,这样也可以作为键,并且不用字符串拼接,但是这样感觉更麻烦。
二.回收站选址
同样用到map的还有一个题目CCF201912-2 回收站选址
代码为:https://tigerisland.blog.csdn.net/article/details/104213820
这个博主写的这个代码非常好,这首先我们来看一下数据范围
从这里我们就知道尝试暴力搜索肯定行不通。但是我们同时也发现坐标数目其实很少,只有1000个,这里我们采用map是非常合适的。首先我们需要建议点的坐标到这个点处是否有垃圾的映射,所以我们就定义了一个map<pair<int, int>, int> ps;用来存储每个点是否有垃圾。
在这个题目中假如问题是给一些点的坐标让我们来判断点的周围是否有垃圾,以此来权衡是否可以作为垃圾回收站的选址的话就不用遍历一遍所有垃圾的地址,只用定义这个map就足矣。
但是这个题目是要求我们找到斜角处不同垃圾数量的垃圾站各自数量,使得我们必须遍历所有的垃圾地点。为了达到这个要求我们又建立了一个数组pair<int, int> p[N];N=1000因为最多有1000个垃圾点,这个实现了从0开始的数组下标到垃圾坐标的映射。
/* CCF201912-2 回收站选址 */
#include <bits/stdc++.h>
using namespace std;
const int N = 1000;
pair<int, int> p[N];
const int CN = 4;
int cnt[CN + 1];
int main()
{
int n;
map<pair<int, int>, int> ps;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
int x, y;
scanf("%d%d", &x, &y);
p[i] = make_pair(x, y);
ps[p[i]] = 1;
}
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < n; i++) {
int x = p[i].first;
int y = p[i].second;
if(ps[make_pair(x, y -1)] && ps[make_pair(x, y + 1)] &&
ps[make_pair(x - 1, y)] && ps[make_pair(x + 1, y)])
cnt[ps[make_pair(x - 1, y - 1)] + ps[make_pair(x - 1, y + 1)] +
ps[make_pair(x + 1, y - 1)] + ps[make_pair(x + 1, y + 1)]]++;
}
for(int i = 0; i <= CN; i++)
printf("%d\n", cnt[i]);
return 0;
}
这个博主写的最后的循环遍历很巧妙
const int CN = 4;
int cnt[CN + 1];
for(int i = 0; i < n; i++) {
int x = p[i].first;
int y = p[i].second;
if(ps[make_pair(x, y -1)] && ps[make_pair(x, y + 1)] &&
ps[make_pair(x - 1, y)] && ps[make_pair(x + 1, y)])
cnt[ps[make_pair(x - 1, y - 1)] + ps[make_pair(x - 1, y + 1)] +
ps[make_pair(x + 1, y - 1)] + ps[make_pair(x + 1, y + 1)]]++;
}
for(int i = 0; i <= CN; i++)
printf("%d\n", cnt[i]);
这个代码中使用了cnt数组来存储分别可作为垃圾站的点的两条对角线上堆放不同垃圾堆数量分别别点的数量。这里正好利用了如果某个点有垃圾ps[]=1,可以1将这些点相加,然后
cnt[ ps[make_pair(x - 1, y - 1)] + ps[make_pair(x - 1, y + 1)] +ps[make_pair(x + 1, y - 1)] + ps[make_pair(x + 1, y + 1)] ]++;
果然,不同的时间看同一道题会有不同的感悟
对回收站选址新的感悟
之前说定义了一个map用来存储(x,y)点和这个点处有没有垃圾这一对应关系的。所以我们对于map的键采用了pair二元有序对的类型,这样才能存储的下坐标的信息。我们又定义了一个p数组,说是为了保存这些垃圾点的地址信息,之前我以为这个数组是必要的,我以为map的键就是整块的,访问不了具体的横坐标和纵坐标的信息才定义这么一个数组来保存这个横纵坐标的信息。
现在我发现我错了,这个其实只有一个map数组我们也能访问到具体的横纵坐标信息。
auto it=ps.begin();
cout<<it->first.first<<' '<<it->first.second;
这样也能访问到具体的横纵夺标,但是显然,这种方式不便于理解,我们也不会闲的去写这种代码,所以创建一个p数组来保存这些信息还是很有必要的。
这里的话创建的p数组数据类型是pair<int int>类型的,我们可能不太熟悉,所以肯定有点陌生。
pair的注意事项
ps[make_pair(x, y -1)]可以看到我们每次要先创建一个pair才可以,不能直接ps[<x, y -1>]
那当我们用三元组作为索引应该怎么办呢?
当然最简便的是创建一个三个变量的结构体来当作键,有人说那是不是pair可以用两个变量的结构体代替。当然可以,但是有缺点。
拿三元结构体为例子。
struct three{
int x;
int y;
int z;
};
int main()
{
map<three,int>ps2;
three key;
key.x=1;key.y=1;key.z=1;
ps2[key]=1;
结果是什么?
事实上会报错,为什么呢?
map中的键必须必须具有严格弱序关系
因为std::map
是基于红黑树实现的,它要求键类型必须具有严格弱序关系。因此,你需要在three
结构体中提供比较操作符,或者使用函数对象来比较对象。所以通常是我们使用单变量,string类型(常用),pair类型(std::pair
已经提供了默认的比较操作符。默认情况下,std::pair
的比较是按照成员变量的字典序进行的。)来作为键。
那你要说我就是要用三元struct结构体来作为键,ok,请看下面
可以看到我们可以通过自定义比较操作符来实现,但是显而易见,好麻烦。
所以对于二元组作为键的话,还是用pair吧,至于三元组作为键的话,可能会有更好的别的方式可以来实现