【美团0408】春招实习笔试练习

美团五道题,一般来说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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值