美团五道题,一般来说4道正常水平
1. 换座位
题目描述:
小团班级的作为排成了n行(行从1到n编号),共有m个大列(大列从1到m编号),每个大列中有a个小列(小列从1到a编号),大列与大列之间有一个过道。小团的班级每周会换一次座位,首先所有同学都换到后一行,最后一行的同学换到第一行,然后所有同学都移动到自己右边的那个大列的相同的小列上,在最右大列的同学移动到最左大列。换句话说,对于坐在第i<n行的同学,新位置在第i+1行,如果i=n那么新位置在第一行;对于坐在第j<m大列的同学,新位置在第j+1大列,如果j=m,那么新位置在第一大列;对于坐在第k小列的同学,新位置仍然在第k小列
小团的学校最近换了一批学生桌椅。这批学生桌椅的有点在于可以调节桌子的高度,一些同学调整了桌子高度,但是另一些没有。这样换座就变得麻烦了起来,如果一位调整了桌子高度的同学换到了未调整桌子同学的位置,他就会调整新位置的桌子到他想要的高度,而一位没有调整桌子高度的同学换到了调整过桌子高度同学的位置,他也会调整新位置的桌子高度,使其恢复原高度。
现在小团的班级要进行换座位了,给出换座位前班级所有桌子的情况,小团想知道,换一次位置后,有多少同学需要重新调整桌子高度
输入描述:
输入第一行包含三个数n,m,a,意义如题目所示
接下来n行,每行m个长度为a的01字符串,表示目前小团班上的桌子情况。其中0表示这个这个位置未调节桌子高度,1表示已调节桌子高度。
对于全部数据,1<=n,m<=200, n * m >=2, 1<=a<=5
样例输入:
3 3 2
01 10 00
10 00 11
01 00 00
样例输出:
8
思路:打卡题,代码比题目短
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
using namespace std;
int main() {
int n, m, a;
cin >> n >> m >> a;
vector<vector<string>> site(n, vector<string>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> site[i][j];
}
}
int res = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int x = (i + 1) % n;
int y = (j + 1) % m;
for (int k = 0; k < a; k++) {
if (site[i][j][k] != site[x][y][k]) res++;
}
}
}
cout << res << endl;
return 0;
}
2. 必经之路
题目描述:
有一颗n个节点的树,有一条边被选定,小美想知道对于所有经过这条边选定边的所有树上简单路径,最长的那条有多长。一条简单的路径长度指这条简单路径上的边的个数
输入描述:
第一行一个整数n,表示树的节点个数。
第二行n-1个整数,第i个整数pi表示节点i+1和pi之间有一条边相连。
第三行两个整数x,y,表示这条选定的边。保证这条边一定是树上的一条边
对于全部数据,2<=n<=105, 1<=pi<=n, 1<=x,y<=n, x不等于y。保证输入数据正确描述一棵树,并且(x, y)是树上的一条边
输出描述:
输出一行,一个整数,表示所有经过选定边的树上简单路径中,最长的那条的长度。
样例输入:
7
1 2 3 4 5 3
3 7
样例输出:
4
思路:简单的遍历,从一个边的两个节点分别找最大值就好了
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
using namespace std;
int maxN = 0;
void dfs(vector<vector<int>> &tree, vector<int> &visited, int root, int length) {
maxN = max(maxN, length);
for (int i = 0; i < tree[root].size(); i++) {
if (visited[tree[root][i]] == 0) {
visited[tree[root][i]] = 1;
dfs(tree, visited, tree[root][i], length + 1);
}
}
}
int main() {
int n;
cin >> n;
vector<vector<int>> tree(n + 5);
for (int i = 2; i <= n; i++) {
int temp;
cin >> temp;
tree[temp].push_back(i);
tree[i].push_back(temp);
}
int x, y;
int res = 0;
cin >> x >> y;
vector<int> visited(n + 5);
visited[x] = 1;
visited[y] = 1;
dfs(tree, visited, y, 0);
res += maxN;
maxN = 0;
dfs(tree, visited, x, 0);
res += maxN;
cout << res + 1;
return 0;
}
3. 水果打包
题目描述:
客户订购了n个水果,并且要求打包成多个果篮,一个果篮最多装m个水果。
为了包装方便,水果按从1到n编号,同一个果篮里装的水果编号必须是连续的。果篮的成本与容积成线性关系,为了估计容积,小美简单的用样本中点估计了一下。具体来说,假设一个果篮中装的最大的水果体积是u,最小的是v,那么这个果篮的成本就是k*floor((u+v)/2)+s,其中k是果篮中装入水果的个数,s是一个常数,floor(x)是下取整函数,比如floor(3.8)=3,floor(2)=2
客户并没有规定果篮的数量,但是希望果篮的成本越小越好,毕竟买水果就很贵了。请求出小美打包这n个水果所用的最小花费
输入描述:
第一行三个正整数n,m,s。
第二行n个正整数a1,a2,...,an,表示每个水果的体积
对于全部数据,1<=n<=104,1<=m<=103,m<=n,1<=ai<=104
输出描述:
输出一个整数,表示打包这n个水果果篮的最小成本
样例输入:
6 4 3
1 4 5 1 4 1
样例输出:
21
思路:dp思路,调调就行
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
using namespace std;
int main() {
int n, m, s;
cin >> n >> m >> s;
vector<int> fruits(n + 5);
for (int i = 1; i <= n; i++) {
cin >> fruits[i];
}
vector<int> dp(n + 5);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int minN = fruits[i];
int maxN = fruits[i];
dp[i] = fruits[i] + s;
for (int j = i - 1; j >= 1; j--) {
minN = min(minN, fruits[j]);
maxN = max(maxN, fruits[j]);
dp[i] = min(dp[i] + dp[j], dp[j - 1] + (i - j + 1) * (minN + maxN) / 2 + s);
}
}
cout << dp[n];
return 0;
}
4. 雷区行走
题目描述:
有一片n*m大小的网格,共n行m列,其中行和列都用从1开始的整数编号,网格中有k个格子中埋有地雷。我们记第a行b列的格子为(a,b)。小美现在位于(x1,y1),她想要移动到(x2,y2)处。小美每次移动可以移动到与她所处格子的相邻一格中,形式化的说,如果小美位于(x,y),则小美可以移动到(x-1,y),(x+1,y),(x,y-1),(x,y+1)的格子之一,但小美不能移动到网格之外
小美想要在移动过程中,离这些地雷越远越好,而不是走最短路径。这里定义两个格子之间的距离为曼哈顿距离,即格子(a,b)和(c,d)之间的距离是|a-c|+|b-d|。小美想知道,移动中与地雷之间距离的最小值最大可能是多少。请注意,如果无论小美如何移动,都会进入一个有地雷的各自的话,这个最大的可能值为0
输入描述:
第一行三个整数n,m,k,分别表示网格的行数,列数和地雷个数
接下来k行,每行两个整数p,q,表示一个地雷放置在格子(p,q)中。任意两地雷的放置位置不同
接下来一行四个整数x1,y1,x2,y2,表示小美的出发位置和目的位置。保证小美的出发位置和目的位置上没有地雷。
对于全部数据,1<=n, m<=500, n*m>=3, 1<=k<=min{n*m-2, 400}, 1<=p,x1,x2<=n, 1<=q,y1,y2<=m, (x1,y1)不等于(x2, y2),保证(x1, y1)和(x2, y2)中没有地雷,并且一个格子中最多放置一个地雷
输出描述:
输出一行一个整数,表示移动过程中与地雷之间距离的最小值的可能最大值
样例输入:
5 6 2
2 1
2 3
1 1 5 1
样例输出:
1
思路:bfs扩展先把地图上的最小值求出来,再使用二分查找找到符合条件的路径最大值,有点烦这个题
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
int n, m, k;
int dx[4] = { 1, -1, 0, 0 };
int dy[4] = { 0, 0, 1, -1 };
int x_1, y_1, x_2, y_2;
bool check(vector<vector<int>> &dist, int length) {
vector<vector<int>> visited(n + 5, vector<int>(m + 5));
queue<vector<int>> q;
q.push({ x_1, y_1 });
visited[x_1][y_1] = 1;
while (!q.empty()) {
int len = q.size();
for (int i = 0; i < len; i++) {
int x = q.front()[0];
int y = q.front()[1];
for (int j = 0; j < 4; j++) {
int tempX = x + dx[j];
int tempY = y + dy[j];
if (tempX >= 1 && tempX <= n && tempY >= 1 && tempY <= m && dist[tempX][tempY] >= length && visited[tempX][tempY] == 0) {
visited[tempX][tempY] = 1;
q.push({ tempX, tempY });
if (tempX == x_2 && tempY == y_2) {
return true;
}
}
}
q.pop();
}
}
return false;
}
int main() {
cin >> n >> m >> k;
vector<vector<int>> dist(n + 5, vector<int>(m + 5, INT_MAX));
queue<vector<int>> booms;
for (int i = 0; i < k; i++) {
int x, y;
cin >> x >> y;
dist[x][y] = 0;
booms.push({ x, y });
}
while (!booms.empty()) {
int len = booms.size();
for (int i = 0; i < len; i++) {
int x = booms.front()[0];
int y = booms.front()[1];
for (int j = 0; j < 4; j++) {
int tempX = x + dx[j];
int tempY = y + dy[j];
if (tempX >= 1 && tempX <= n && tempY >= 1 && tempY <= m && dist[x][y] + 1 < dist[tempX][tempY]) {
dist[tempX][tempY] = dist[x][y] + 1;
booms.push({ tempX, tempY });
}
}
booms.pop();
}
}
cin >> x_1 >> y_1 >> x_2 >> y_2;
int l = 0, r = min(dist[x_1][y_1], dist[x_2][y_2]);
while (l < r) {
int mid = (l + r + 1) >> 1;
if (check(dist, mid)) l = mid;
else r = mid - 1;
}
cout << l;
return 0;
}
5. 多彩的树
题目描述:
有一颗n个节点的树,树上每个点都有红绿蓝三种颜色中的一种。定义一棵树是多彩的,当且仅当这棵树同时存在一个红色节点,一个蓝色节点和一个绿色节点。
保证最初这棵树是多彩的,现在要砍掉这棵树的某一条边,请问有多少种砍法,使得砍完之后形成的两棵树都是多彩的
输入描述:
第一行一个整数n,表示节点个数。
第二行n-1个整数p2,p3,...,pn,pi表示树上i和pi两点之间有一条边。保证给出的一定是一棵树
第三行一个长度n的字符串,第i个字符表示第i个节点的初始颜色。其中R表示红色,G表示绿色,B表示蓝色。保证字符串只能由这三种大写字母构成
对于全部数据,3<=n<=105
输出描述:
输出一行,一个正整数,表示答案
样例输入:
7
1 2 3 1 5 5
GBGRRBB
样例输出:
1
思路:递归完事,从子节点向上更新
#include <iostream>
#include <vector>
#include <unordered_map>
#include <string>
using namespace std;
vector<int> dfs(vector<vector<int>> &tree, vector<vector<int>> &color, int root) {
if (tree[root].size() == 0) {
return color[root];
}
for (int i = 0; i < tree[root].size(); i++) {
vector<int> temp = dfs(tree, color, tree[root][i]);
color[root][0] += temp[0];
color[root][1] += temp[1];
color[root][2] += temp[2];
}
return color[root];
}
int main() {
int n;
cin >> n;
vector<vector<int>> tree(n + 5);
for (int i = 2; i <= n; i++) {
int temp;
cin >> temp;
tree[temp].push_back(i);
}
unordered_map<int, char> hash_map;
vector<vector<int>> color(n + 5, vector<int>(3));
string s;
cin >> s;
for (int i = 0; i < s.size(); i++) {
hash_map[i + 1] = s[i];
if (s[i] == 'R') {
color[i + 1][0] += 1;
}
else if (s[i] == 'G') {
color[i + 1][1] += 1;
}
else {
color[i + 1][2] += 1;
}
}
dfs(tree, color, 1);
int res = 0;
for (int i = 2; i <= n; i++) {
int x, y, z;
x = color[1][0] - color[i][0];
y = color[1][1] - color[i][1];
z = color[1][2] - color[i][2];
if (x > 0 && y > 0 && z > 0 && color[i][0] > 0 && color[i][1] > 0 && color[i][2] > 0) {
res++;
}
}
cout << res;
return 0;
}