网易2021校招笔试-算法工程师(正式第二批)
… 也不知道考这么多图论干嘛
测试链接
01 - [编程题]项目经理
A公司和B公司有n个合作的子项目,每个子项目由A公司和B公司各一名员工参与。一名员工可以参与多个子项目。
一个员工如果担任了该项目的项目经理,它需要对所参与的该项目负责。一个员工也可以负责多个项目。
A公司和B公司需要保证所有子项目都能有人负责,问最少需要指定几名项目经理?
输入描述:
第一行为A公司的的人员id列表, 0< id数量 < 10000,用空格切分
第二行为B公司的人员id列表, 0< id数量 < 10000,用空格切分
第三行为有已经有多少个匹配数子项目合作关系n
下面有n行,每一行为每个子项目的合作对应关系,为两个id,第一个为A公司的员工id,第二个为B公司的员工id,用空格区分
输出描述:
一个整数,A公司和B公司合起来至少需要指定几名项目经理
输入例子1:
0 1 2
3 4 5
6
0 4
0 3
1 3
1 4
2 5
2 4
输出例子1:
3
例子说明1:
可行的一个保留人员方案是留下0,1,2即可,这样即可保证所有的子项目都有人cover到
二分图的最小覆盖点问题(没见过怎么可能想得到)
二分图的最大匹配问题,最少覆盖点问题,最少边覆盖问题,最大独立集问题 都是匈牙利算法
注意有两个程序的细节:
- 未指定输入个数在c++怎么读入: stringstream 注意cin 之后再读入要提前把
\n
读进去 - 输入节点是从0开始的 但匈牙利算法是以0作为未匹配标志 这里把所有点的编号整体向后移动一位
#pragma GCC optimize(3)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std;
const int N = 10010, M = 20020;
int n1, n2, m;
int h[N], e[M], ne[M], idx;
int match[N];
bool st[N];
int node1[N], node2[N];
// 匈牙利算法
bool find(int x)
{
for(int i = h[x]; ~i; i = ne[i])
{
int j = e[i];
if(!st[j])
{
st[j] = true;
if(match[j] == 0 || find(match[j]))
{
match[j] = x;
return true;
}
}
}
return false;
}
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int main()
{
memset(h, -1, sizeof h);
int x1, x2;
string line;
getline(cin, line);
stringstream ss(line);
while(ss >> x1)
{
node1[++n1] = x1 + 1;
}
getline(cin, line);
stringstream ss2(line);
while(ss2 >> x2)
{
node2[++n2] = x2 + 1;
}
cin >> m;
while(m--)
{
int a, b;
cin >> a >> b;
add(a + 1, b + 1);
}
int res = 0;
for(int i = 1; i <= n1; i++)
{
int x = node1[i];
memset(st, false, sizeof st);
if(find(x)) res++;
}
printf("%d\n", res);
return 0;
}
02 - [编程题]分割字符串的最大得分
给你一个由若干 0 和 1 组成的字符串s,请你计算并返回将该字符串分割成两个子字符串(即左子字符串和右子字符串, 子字符串允许为空)所能获得的最大得分。
已知分割字符串的得分规则如下:
左子字符串中:0得2分,1得1分
右子字符串中:1得2分,0得1分
子字符串为空则得0分
输入描述:
一行包括一个由0和1组成的字符串s
输出描述:
一行一个整数表示答案。
输入例子1:
011101
输出例子1:
11
例子说明1:
当左子字符串 = “0” 且 右子字符串 = “11101”,得分最大= 2+ 9 = 11
输入例子2:
00111
输出例子2:
10
例子说明2:
当左子字符串 = “00” 且右子字符串 = “111” 时,得分最大 = 4 + 6 = 10
前后缀分解了 很经典的前后缀分解问题 分别预处理前缀分数和后缀分数 枚举中点即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
int main()
{
string line;
getline(cin, line);
int n = line.size();
line = " " + line;
vector<int> f(n + 2, 0), g(n + 2, 0);
// 预处理 f 和 g (递推)
for(int i = 1; i <= n; i++)
{
f[i] = f[i - 1] + 1;
if(line[i] == '0') f[i] += 1;
}
for(int i = n; i >= 1; i--)
{
g[i] = g[i + 1] + 1;
if(line[i] == '1') g[i] += 1;
}
// 前后缀分解 :枚举中点
int res = 0;
for(int i = 0; i <= n; i++)
res = max(res, f[i] + g[i + 1]);
printf("%d", res);
return 0;
}
03 - [编程题]电影院选座
疫情逐步缓和后,电影院终于开业了,但是由于当前仍处于疫情期间,应尽量保持人群不聚集的原则。
所以当小易来电影院选定一排后,尽量需要选择一个远离人群的位置。
已知由0和1组成的数组表示当前排的座位情况,其中1表示已被选座,0表示空座
请问小易所选座位和最近人的距离座位数最大是多少?
有如下假设:至少有一个人已选座,至少有一个空座位,且座位数限制为
输入描述:
一行由0和1组成的整数数组
输出描述:
仅一行一个整数表示答案
输入例子1:
1 0 0 0 1 0 1
输出例子1:
2
例子说明1:
小易第3个座位最合适,则和座位1/座位5的距离为2
输入例子2:
1 0 1 0 1
输出例子2:
1
例子说明2:
小易可以选择第2个座位或者第4个座位,距离为1
贪心吗 最大连续0的个数除以二上取整?
要注意的边界情况就是 0 0 0 0 0 1
这里的最大距离是5 所以两边的0要特判一下
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
const int N = 1010;
int n = 0;
int nums[N];
int main()
{
int x;
while(cin >> x)
{
nums[++n] = x;
}
// 统计连续0的个数
int zeros = 0, res = 0;
bool first = true;
for(int i = 1; i <= n; i++)
{
if(nums[i] == 0)
zeros++;
// "前导0"的特判
else if(first)
{
res = max(res, zeros);
zeros = 0;
first = false;
}
else{
res = max(res, (zeros + 1) / 2);
zeros = 0;
}
}
// "后导0"的特判
res = max(res, zeros);
printf("%d\n", res);
return 0;
}
04 - [编程题]仓库配送
网易严选建有N个自营仓分布在全国各地,标记为仓库1到N。
给定一个配货时间组(v,u,w),v为出发仓库,u为目标仓库,w为从出发仓库到目标仓库的耗时时间。可能存在仓库间过远,无法支持调拨转货。
指定一个出发仓库K,我们需要将供应商发送到K仓库的货配送到各个仓库。问配送到所有可到达仓库所要最短时间?如果无法全部调拨到,则返回-1.
输入描述:
第一行三个正整数,由空格分割,分别表示仓库个数N,出发仓K,以及配送时间组个数M
接下来 M行,每行三个整数,由空格分割,分别表示(v,u,w)三个数,v为出发仓库,u为目标仓库,w为从出发仓库到目标仓库的耗时时间
输出描述:
一行一个数字表示答案,配送到所有可达仓库到最短时间
输入例子1:
6 2 5
2 1 1
2 6 2
1 3 3
3 4 1
6 5 2
输出例子1:
5
比第一题简单多了… 这题是最短路的板子题 所有最短路的最大值罢了
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
using PII = pair<int, int>;
const int N = 10010, M = 50050;
int n, m, target;
int h[N], e[M], w[M], ne[M], idx;
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dijkstra()
{
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.emplace(0, target);
dist[target] = 0;
while(heap.size())
{
PII t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if(st[ver]) continue;
st[ver] = true;
for(int i = h[ver]; ~i; i = ne[i])
{
int j = e[i];
if(dist[j] > distance + w[i])
{
dist[j] = distance + w[i];
heap.emplace(dist[j], j);
}
}
}
}
int main()
{
memset(dist, 0x3f, sizeof dist);
memset(h, -1, sizeof h);
memset(st, false, sizeof st);
scanf("%d%d%d", &n, &target, &m);
while(m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
dijkstra();
int res = 0;
for(int i = 1; i <= n; i++)
{
if(dist[i] == 0x3f3f3f3f)
{
res = -1;
break;
}
res = max(res, dist[i]);
}
printf("%d", res);
return 0;
}