2022阿里笔试编程题ak口糊(4月15日)
写代码20分钟ak,但前面选择题基本全忘了(((
\(A\):签到
\(B\):对每个非'.'位置下、右、右斜上、右斜下方向分别去check4个是否相同即可
\(C\):n<=2000,考虑类似树形背包的转移:
- 对于每个点,其子树之间必没有父子关系,求每个点所有子树之间的答案取min就是最终答案
- 每个点所有节点的值组成一个集合,这个集合是可以dfs去dp的
但\(a_i<=1000(应该是?), n<=2000\),开数组去存集合不太行,并且求答案需要比较快速。所以对于每个点,开了个set放入已经check完的所有子树,把没check的子树中的点\(x\)在这个set里lower_bound拿到相对近的值的指针,再prev一下,拿到这两个值(如果存在)与x做差取绝对值然后对ans取min,最后按子树顺序把子树插入到check完了的集合里面。(写的好抽象,看代码即可)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int v[2005];
vector<int>G[2005];
int ans = 1e9;
set<int> dfs(int from, int fa) {
set<int>now;
for (auto& to : G[from]) {
if (to == fa)continue;
auto tmp = dfs(to, from);
v[from] += v[to];
for (auto i : tmp) {
auto p = now.lower_bound(i);
if (p != now.end()) {
ans = min(ans, abs(*p - i));
}
if (p != now.begin()) {
ans = min(ans, abs(*prev(p) - i));
}
}
for (auto i : tmp)
now.insert(i);
}
now.insert(v[from]);
return now;
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
for (int i = 1; i < n; i++) {
int x, y;
cin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1, 0);
cout << ans;
return 0;
}
总结:暴力即可