map && multimap
map
map 的意思是映射。用法一般是
map<char, int>mp
按照我的理解,map 类似于一个高级的数组。前面的数据类型 char 相当于下脚标,而数组元素的值就对应着后面的类型 int。例如可以用一个 map<string, int>month_name 来表示“月份名字对应的月份编号“。然后用 month_name["july"] = 7 这样的方式来赋值。所以说,”高级的数组“指下脚标和元素类型可以是任意数据类型的(当然包括结构体)。
接下来说说基本操作
1.声明,赋值
除了上面已经讲过的像数组元素那样赋值的方法, 还支持这样 mp.insert(make_pair(”july“, 7)); (不过当然是上面的方法简单)
2.查找
和 set 很像:if (mp.find('f') == mp.end()) ......,若找不到,就执行 if 里面的语句。(找的是下脚标,不是元素的值)
3. 输出大小
同理 set :mp.size()
4.遍历
1 #include <bits/stdc++.h> 2 using namespace std; 3 map<char, int>mp; 4 int main() 5 { 6 for (int i = 0; i < 5; i++) mp['a' + i] = i; 7 for (map<char, int>::iterator it = mp.begin(); it != mp.end(); ++it) 8 printf("%c %d\n", it -> first, it -> second); 9 /*若嫌麻烦,也可在前面用 typedef 改个名,以后遍历就不用写一串了 10 typedef map<char, int>::iterator mcit; 11 for(mcit it = mp.begin(); it != mp.end(); ++it) */ 12 return 0; 13 }
输出:
a 0
b 1
c 2
d 3
e 4
还有 first 就是指“下脚标”, second 指”数组元素值“。
5.删除
和 set 一样
mp.erase('f'); 或 map<char, int>::iterator it = mp.find('f'); mp.erase(it);
6. lower_bound() 和 upper_bound()
map<char, int>::iterator it1 = mp.lower_bound('f'); printf("%c %d\n", it1->first, it1->second); 就这样
7.!注意 !
看这段代码
1 #include <bits/stdc++.h> 2 using namespace std; 3 map<char, int>mp; 4 int main() 5 { 6 for (int i = 0; i < 5; i++) mp['a' + i] = i; 7 cout << mp['z'] << endl; 8 for (map<char, int>::iterator it = mp.begin(); it != mp.end(); ++it) 9 printf("%c %d\n", it -> first, it -> second); 10 return 0; 11 }
在第7行,我们发现 mp['z'] 根本没有,然而这是能过编译的!而且输出时,结果是这样的:
0
a 0
b 1
c 2
d 3
e 4
z 0
可见 mp['z'] 的值是0。而且这个 mp['z'] 也被自动添加到了 mp 中,看来c++是自己在 mp 中创建了一个 mp['z']。所以我们凡是要对 map 进行操作时,都要首先确认这个元素是否存在,否则就会出现这些像意想不到的错误。
multimap
multimap的用法几乎map一样,唯一不同的是,它里面的元素是可以重的。
所以两种删除方法在这里就不一样了:
1.mp.erase('f'):删除multimap中所有以'f'为下标的元素。
2. map<char, int>::iterator it = mp.find('f'); erase(it):只删除第一个‘’f.
应用
1.map可以代替hash
虽然复杂度多了一个log,但是在时间充裕而且代码比较长的情况下,用map写就显得极为方便。
举一个很水的例子:洛谷P3370 【模板】字符串哈希
1 #include<cstdio> 2 #include<string> 3 #include<map> 4 using namespace std; 5 6 map<string, bool> mp; 7 int n, cnt = 0; 8 char s[1505]; 9 10 int main() 11 { 12 scanf("%d", &n); 13 for(int i = 1; i <= n; ++i) 14 { 15 scanf("%s", s); 16 if(!mp[s]) mp[s] = 1, cnt++; 17 } 18 printf("%d\n", cnt); 19 return 0; 20 }
2.解决一些比较麻烦的记录问题
如果你看不懂这个标题在说啥,说明我语文学得不好。不管了,直接上题:家谱
这道题确实是并查集水题,但是我们要记录出现过的字符串,这时候就是map大显神威的时候了。我这篇博客里讲的挺细的,简单易懂。
不过里面可以不用string类型输入,而用字符数组,只不过map的类型是map<string, int>。
3.优!化!
别看map带一个log,但在某些情况下还能优化!
没错,去年的辽宁省选Day1T1。
解法是对抗搜索,但这不是我们今天的重点。
暴力的搜索还要判断每一行的状态,多了一层复杂度,导致后几个点TLE。如果把状态压成一个数的话不仅数组装不下,int都会爆。因此我们把表示状态的long long当成map的下标,然后找状态的时候时间复杂度成功降到了logn。虽然不是最优的,但是AC已经绰绰有余了。最重要的是,这个优化也别好想,随手就是一加。
放个代码吧(有人是不是想c-c + c-v瞬间A题)
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<map> 8 using namespace std; 9 typedef long long ll; 10 const int maxn = 15; 11 //mrclr 12 13 struct Node 14 { 15 int x, y; 16 }a[maxn][maxn]; 17 struct Node2 18 { 19 int xx, yy, cha2; 20 bool operator < (const Node2& other)const 21 { 22 return cha2 < other.cha2; 23 } 24 }; 25 int n, m; 26 const int INF = 0x3f3f3f3f; 27 struct Node3 28 { 29 int a[maxn]; 30 ll encode()const 31 { 32 ll ret = 0; 33 for(int i = 1; i <= n; ++i) {ret |= a[i]; ret <<= 5;} 34 return ret; 35 } 36 37 }chess; 38 map<ll, int> mpMax, mpMin; 39 int Minsearch(const Node3& chess); 40 int Maxsearch(const Node3& chess) 41 { 42 if(chess.a[n] == m) return 0; 43 if(mpMax.find(chess.encode()) != mpMax.end()) return mpMax[chess.encode()]; 44 int Max = -INF; 45 for(int i = 1; i <= n; ++i) 46 if(chess.a[i] < chess.a[i - 1]) 47 { 48 Node3 _ch = chess; 49 _ch.a[i]++; 50 Max = max(Max, a[i][_ch.a[i]].x + Minsearch(_ch)); 51 } 52 return mpMax[chess.encode()] = Max; 53 } 54 int Minsearch(const Node3& chess) 55 { 56 if(chess.a[n] == m) return 0; 57 if(mpMin.find(chess.encode()) != mpMin.end()) return mpMin[chess.encode()]; 58 int Min = INF; 59 for(int i = 1; i <= n; ++i) 60 if(chess.a[i] < chess.a[i - 1]) 61 { 62 Node3 _ch = chess; 63 _ch.a[i]++; 64 Min = min(Min, -a[i][_ch.a[i]].y + Maxsearch(_ch)); 65 } 66 return mpMin[chess.encode()] = Min; 67 } 68 int main() 69 { 70 scanf("%d%d", &n, &m); 71 for(int i = 1; i <= n; ++i) 72 for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j].x); 73 for(int i = 1; i <= n; ++i) 74 for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j].y); 75 for(int i = 1; i <= n; ++i) chess.a[i] = 0; 76 chess.a[0] = m; 77 printf("%d\n", Maxsearch(chess)); 78 return 0; 79 }
map讲到这里就算讲完了,如果有更好的用法,欢迎在下面评论,或者当面diss mrclr。