首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

美团2024年春招第一场笔试 C++

  • 25-04-25 14:01
  • 3351
  • 12073
blog.csdn.net

目录

1,小美的平衡矩阵

2,小美的数组询问

3,小美的MT

 4,小美的朋友关系


1,小美的平衡矩阵

 【题目描述】

给定一个n*n的矩阵,该矩阵只包含数字0和1。对于 每个i(1<=i<=n),求在该矩阵中,有多少个i*i的区域满足0的个数等于1的个数???

【题目解析】

示例演示:

 如上图,1*1的区域结果为0,2*2的区域结果为7。

算法:前缀和+遍历

题目中给的数据范围是n<=200,所以可以直接遍历数组。

维护 一个前缀和数组统计以(x,y)这个点为右下角,以(1,1)这个点为左上角,这个区域中所有元素的和,由于数组中的数要么是0,要么是1,所以前缀和就表示某个区域中1的个数。

有了前缀和数组,就可以快速 求出某个区域中1的个数,如图:

而这个区域的大小我们是知道的,假设是k,那么这个区域的元素个数就是k*k。如果满足这个区间中1的个数等于k*k/2,那么说明 这个区间中0和1的个数 相等。而1的个数我们可以通过前缀和来表示。

同时还有一点,如果k为奇数,那么k*k的区域中元素个数一定为奇数 ,所以0和1的个数一定不相等。直接输出0即可。

 注意:在输入数据的时候,如果是以整数的形式接受,那么不建议使用cin,因为cin会把第一行的所有数据读成一个整数。就比如 上面的示例,第一行会被读成一个整数1010,而我们期望是读到4个整数的,这是可以使用scanf("%1d",&a),使用 %1d占位符可以确保读到的第一行是4个整数。

【代码】

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. const int N = 205;
  5. int arr[N][N], s[N][N];
  6. //s为前缀和数组
  7. //统计矩形(1,1)到(n,n)中1的数量
  8. int main()
  9. {
  10. int n = 0;
  11. cin >> n;
  12. for(int i=1;i<=n;i++)
  13. for (int j = 1; j <= n; j++)
  14. {
  15. scanf("%1d", &arr[i][j]);
  16. s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + arr[i][j];
  17. }
  18. cout << 0 << endl;
  19. for (int k = 2; k <= n; k++)
  20. {
  21. if (k & 1)
  22. {
  23. cout << 0 << endl;
  24. continue;
  25. }
  26. int ans = 0;
  27. for(int i=1;i+k-1<=n;i++)
  28. for (int j = 1; j+k-1 <= n; j++)
  29. {
  30. //(i,j)是左上角,需要我们计算出k*k这个区域右下角的坐标
  31. int x = i + k - 1;
  32. int y = j + k - 1;
  33. if (s[x][y] - s[i - 1][y] - s[x][j - 1] + s[i - 1][j - 1] == k * k / 2)
  34. ans++;
  35. }
  36. cout << ans << endl;
  37. }
  38. return 0;
  39. }

2,小美的数组询问

 直接遍历即可 

  1. #include <iostream>
  2. using namespace std;
  3. const int N=1e5+10;
  4. int arr[N];
  5. int main()
  6. {
  7. int n=0,q=0;
  8. cin>>n>>q;
  9. long long sum=0,count=0;
  10. for(int i=1;i<=n;i++)
  11. {
  12. cin>>arr[i];
  13. sum+=arr[i];
  14. if(arr[i]==0)
  15. count++;
  16. }
  17. int l,r;
  18. while(q--)
  19. {
  20. cin>>l>>r;
  21. cout<<sum+count*l<<" "<<sum+count*r<<endl;
  22. }
  23. return 0;
  24. }

3,小美的MT

统计元字符中 有多少个M和T,再加上最多可以修改 多少个即可。

  1. //小美的MT
  2. #include <iostream>
  3. #include <string>
  4. using namespace std;
  5. int main()
  6. {
  7. int n = 0, k = 0;
  8. cin >> n >> k;
  9. string str;
  10. cin >> str;
  11. int ans = 0;
  12. for (int i = 0; i < n; i++)
  13. {
  14. if (str[i] == 'M' || str[i] == 'T')
  15. ans++;
  16. }
  17. if (k > n - ans)
  18. cout << n << endl;
  19. else
  20. cout << ans + k << endl;
  21. return 0;
  22. }

 4,小美的朋友关系

 【题目描述】

总人数为n,编号u和v的人之间存在朋友关系,在这n个人中,存在m个朋友关系。

对于这些关系,进行q次事件,格式为【op,u,v】,其中u和v表示人的编号。op表示要进行哪种操作,当op==1时,u和v的朋友关系淡忘,也就是断开u和v的朋友关系。当op==2时,表示查询u和v是否可以建立朋友关系,可以通过第三方或者本来就是朋友关系。

针对每次的op==2操作,返回一个结果Yes or No,表示是否可以建立朋友关系 。

【思路】

这n个人中存在许多的朋友关系,比如编号1-5是朋友,编号6-10是朋友,这两个关系是独立的集合,所以可以想到的是使用并查集来记录朋友关系。

并查集传送门:

【算法与数据结构】并查集详解+题目_并查集结构体-CSDN博客

 并查集中的每个集合可以看成是一棵树,独立多个集合,就是多个独立的树。每个树的根节点也就是每个集合的父节点。


刚开始我的思路是将这m个朋友关系,使用并查集来存储。

但是在q次操作中,op=2是查询是否可以 建立朋友关系的操作,这个简单,只需判断这两个人是否在同一个集合中,也就是这两个人的父节点是否相同。但是对于op=1删除朋友关系操作,比较困难,因为并查集擅于进行 添加关系操作的,不好处理删除节点关系。所以在删除朋友关系这里出现了问题。

我们可以试着把删除朋友关系变成添加朋友关系。这样并查集就可以做了。那么怎么实现呢?

我们可以先将这m个朋友关系用特定的容器存储下来,首先遍历q次操作,遇到删除操作(u,v),在容器中删除(u,v)。

注意:这里删除的时候,要删除的朋友关系是(u,v),有可能存储的时候,朋友关系是(u,v),也有可能是(v,u),这些都是要删除的。

遇到op=2时,不进行操作。一次操作完成后,将该次操作用数组记录下来【op,u,v】。


顺序遍历完后,此时将容器中剩余的朋友关系,构建并查集。 然后逆序遍历记录操作的数组,遇到op=1时,就添加朋友关系,遇到op=2时,就查询朋友关系,判断父节点是否相等即可。

 【代码】

  1. //小美的朋友关系
  2. #include <iostream>
  3. #include <vector>
  4. #include <set>
  5. using namespace std;
  6. const int N = 1e5;
  7. //总人数,初始的朋友关系数,事件数量
  8. int n, m, q;
  9. vector<int> parent;//并查集
  10. set<pair<int, int>> st;//存储初始的朋友关系
  11. //存储事件
  12. struct node
  13. {
  14. int op, u, v;
  15. }arr[N+5];
  16. //找父节点,路径压缩
  17. int find(int x)
  18. {
  19. if (parent[x] != x)
  20. parent[x] = find(parent[x]);
  21. return parent[x];
  22. }
  23. //合并
  24. void unite(int x, int y)
  25. {
  26. int rootX = find(x);
  27. int rootY = find(y);
  28. if (rootX == rootY)
  29. return;
  30. parent[rootX] = rootY;
  31. }
  32. int main()
  33. {
  34. cin >> n >> m >> q;
  35. //初始化并查集
  36. parent.resize(n + 1);
  37. for (int i = 1; i <= n; i++)
  38. parent[i] = i;
  39. //存储关系
  40. int op,u, v;
  41. while (m--)
  42. {
  43. cin >> u >> v;
  44. st.insert({ u,v });
  45. }
  46. int num = 0;
  47. while (q--)
  48. {
  49. cin >> op >> u >> v;
  50. //处理删除操作
  51. if (op == 1)
  52. {
  53. if (st.find({ u,v }) != st.end())
  54. st.erase({ u,v });
  55. else if (st.find({ v,u }) != st.end())
  56. st.erase({ v,u });
  57. else
  58. continue;//说明u和v表示朋友关系,此次删除操作无意义,不需要存储下来
  59. }
  60. //记录操作
  61. arr[num++] = { op,u,v };
  62. }
  63. //删除关系完成后,剩余的元素是没有进行操作的
  64. //构建并查集
  65. for (auto [u, v] : st)
  66. unite(u, v);
  67. vector<bool> ans;//记录最终结果
  68. //逆序遍历操作
  69. //如果是删除就进行合并
  70. //如果是查询就进行判断是否在同一个集合
  71. for (int i = num - 1; i >= 0; i--)
  72. {
  73. op = arr[i].op, u = arr[i].u, v = arr[i].v;
  74. if (op == 1)
  75. {
  76. //合并
  77. unite(u, v);
  78. }
  79. else
  80. {
  81. //判断
  82. ans.emplace_back(find(u) == find(v));
  83. }
  84. }
  85. for (int i = ans.size() - 1; i >= 0; i--)
  86. if (ans[i])
  87. cout << "Yes" << endl;
  88. else
  89. cout << "No" << endl;
  90. return 0;
  91. }

上述代码是使用vector来实现并查集的,题目中的数据范围n是1e9,如果使用vector,就需要开辟1e9个空间,会超出内存限制。所以这里实现并查集的时候,需要使用map来替代。存储当前节点和它的父节点。具体原因,看下方:

初始时,每个节点的父节点就是自己本身。比如mp[1]=1。


当我们逆序遍历时,当遇到op=2,查询朋友关系时,给的两个朋友编号u和v,之前可能没初始化。比如n=10,给了3个朋友关系(1,3),(3,2),(4,6),当我们查询的时候,可能查询的是(5,7),这两个节点没有初始化,也就是mp[5]=0,mp[7]=0,可以发现这两个节点的父节点都是0,如果直接判断,得到的结果是可以构成朋友关系,但本质是不能构成朋友关系的。


也可以看下方代码的初始化部分,我们只初始化了存在朋友关系的节点,其他的节点没有初始化,他们的父节点默认就是0。如果我们开始将所有节点都初始化好,那么就会超出内存限制,那么就和使用vector一样了,甚至占用的内存比vector还要大,所以我们不能一次性就初始还所有节点。而是当遇到一个没初始化的节点,就初始化即可。


所以在查询操作的时候,如果mp[u]=0,或者mp[v]=0,就把这两个值做一下初始化mp[u]=u或者mp[v]=v,这样在判断的时候就不会出错了。


而如果使用的是vector来表示并查集,是不需要考虑这个问题的,因为vector会开辟n个空间,将所有人都初始化好,父节点就是自己。而使用map来存储,只会存储存在朋友关系的节点,如果出现一个新的节点,需要我们自己再初始化。这也就是map不会超出内存限制而vector会超出内存限制的原因。

 【代码】

  1. //小美的朋友关系
  2. #include <iostream>
  3. #include <vector>
  4. #include <map>
  5. #include <set>
  6. using namespace std;
  7. const int N = 1e5;
  8. //总人数,初始的朋友关系数,事件数量
  9. int n, m, q;
  10. map<int,int> parent;//并查集
  11. set<pair<int, int>> st;//存储初始的朋友关系
  12. //存储事件
  13. struct node
  14. {
  15. int op, u, v;
  16. }arr[N + 5];
  17. //找父节点,路径压缩
  18. int find(int x)
  19. {
  20. if (parent[x] != x)
  21. parent[x] = find(parent[x]);
  22. return parent[x];
  23. }
  24. //合并
  25. void unite(int x, int y)
  26. {
  27. int rootX = find(x);
  28. int rootY = find(y);
  29. if (rootX == rootY)
  30. return;
  31. parent[rootX] = rootY;
  32. }
  33. int main()
  34. {
  35. cin >> n >> m >> q;
  36. //初始化并查集和关系集合
  37. int op, u, v;
  38. for (int i = 0; i < m; i++)
  39. {
  40. cin >> u >> v;
  41. parent[u] = u;
  42. parent[v] = v;
  43. st.insert({ u,v });
  44. }
  45. int num = 0;
  46. while (q--)
  47. {
  48. cin >> op >> u >> v;
  49. //处理删除操作
  50. if (op == 1)
  51. {
  52. if (st.find({ u,v }) != st.end())
  53. st.erase({ u,v });
  54. else if (st.find({ v,u }) != st.end())
  55. st.erase({ v,u });
  56. else
  57. continue;//说明u和v表示朋友关系,此次删除操作无意义,不需要存储下来
  58. }
  59. //记录操作
  60. arr[num++] = { op,u,v };
  61. }
  62. //删除关系完成后,剩余的元素是没有进行操作的
  63. //构建并查集
  64. for (auto [u, v] : st)
  65. unite(u, v);
  66. vector<bool> ans;//记录最终结果
  67. //逆序遍历操作
  68. //如果是删除就进行合并
  69. //如果是查询就进行判断是否在同一个集合
  70. for (int i = num - 1; i >= 0; i--)
  71. {
  72. op = arr[i].op, u = arr[i].u, v = arr[i].v;
  73. if (op == 1)
  74. {
  75. //合并
  76. unite(u, v);
  77. }
  78. else
  79. {
  80. //parent[u]==0,说明该节点第一次出现,初始化为u
  81. if (parent[u] == 0)
  82. parent[u] = u;
  83. if (parent[v] == 0)
  84. parent[v] = v;
  85. //判断
  86. ans.emplace_back(find(u) == find(v));
  87. }
  88. }
  89. for (int i = ans.size() - 1; i >= 0; i--)
  90. if (ans[i])
  91. cout << "Yes" << endl;
  92. else
  93. cout << "No" << endl;
  94. return 0;
  95. }

注:本文转载自blog.csdn.net的小鬼yalo的文章"https://blog.csdn.net/2401_82677021/article/details/147401238"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top