力扣--二进制枚举
题目:
我们有 n 栋楼,编号从 0 到 n - 1 。每栋楼有若干员工。由于现在是换楼的季节,部分员工想要换一栋楼居住。
给你一个数组 requests ,其中 requests[i] = [fromi, toi] ,表示一个员工请求从编号为 fromi 的楼搬到编号为 toi 的楼。
一开始 所有楼都是满的,所以从请求列表中选出的若干个请求是可行的需要满足 每栋楼员工净变化为 0 。意思是每栋楼 离开 的员工数目 等于 该楼 搬入 的员工数数目。比方说 n = 3 且两个员工要离开楼 0 ,一个员工要离开楼 1 ,一个员工要离开楼 2 ,如果该请求列表可行,应该要有两个员工搬入楼 0 ,一个员工搬入楼 1 ,一个员工搬入楼 2 。
请你从原请求列表中选出若干个请求,使得它们是一个可行的请求列表,并返回所有可行列表中最大请求数目。
解答:
我们可以通过回溯的方式枚举每一个请求是否被选择。
定义函数 \text{dfs}(\textit{pos})dfs(pos) 表示我们正在枚举第 \textit{pos}pos 个请求。同时,我们使用数组 \textit{delta}delta 记录每一栋楼的员工变化量,以及变量 \textit{cnt}cnt 记录被选择的请求数量。
对于第 \textit{pos}pos 个请求 [x,y][x,y],如果选择该请求,那么就需要将 \textit{delta}[x]delta[x] 的值减 11,\textit{delta}[y]delta[y] 的值加 11,\textit{cnt}cnt 的值加 11;如果不选择该请求,则不需要进行任何操作。在这之后,我们调用 \text{dfs}(\textit{pos}+1)dfs(pos+1) 枚举下一个请求。
如果我们枚举完了全部请求,则需要判断是否满足要求,也就是判断 \textit{delta}delta 中的所有值是否均为 00。若满足要求,则更新答案的最大值。
代码实现时,可以在修改 \textit{delta}delta 的同时维护 \textit{delta}delta 中的 00 的个数,记作 \textit{zero}zero,初始值为 nn。如果 \textit{delta}[x]delta[x] 增加或减少前为 00,则将 \textit{zero}zero 减 11;如果 \textit{delta}[x]delta[x] 增加或减少后为 00,则将 \textit{zero}zero 加 11。
Python3C++JavaC#GolangCJavaScript
class Solution {
private:
vector<int> delta;
int ans = 0, cnt = 0, zero, n;
public:
void dfs(vector<vector<int>> &requests, int pos) {
if (pos == requests.size()) {
if (zero == n) {
ans = max(ans, cnt);
}
return;
}
// 不选 requests[pos]
dfs(requests, pos + 1);
// 选 requests[pos]
int z = zero;
++cnt;
auto &r = requests[pos];
int x = r[0], y = r[1];
zero -= delta[x] == 0;
--delta[x];
zero += delta[x] == 0;
zero -= delta[y] == 0;
++delta[y];
zero += delta[y] == 0;
dfs(requests, pos + 1);
--delta[y];
++delta[x];
--cnt;
zero = z;
}
int maximumRequests(int n, vector<vector<int>> &requests) {
delta.resize(n);
zero = n;
this->n = n;
dfs(requests, 0);
return ans;
}
};
复杂度分析
时间复杂度:O(2^m)O(2
m
),其中 mm 是数组 \textit{requests}requests 的长度,即请求的数量。从 mm 个请求中任意选择请求的方案数为 2^m2
m
,对于每一种方案,我们需要 O(1)O(1) 的时间判断其是否满足要求。
空间复杂度:O(m+n)O(m+n)。递归需要 O(m)O(m) 的栈空间,数组 \textit{delta}delta 需要 O(n)O(n) 的空间。
方法二:二进制枚举
我们可以使用一个长度为 mm 的二进制数 \textit{mask}mask 表示所有的请求,其中 \textit{mask}mask 从低到高的第 ii 位为 11 表示选择第 ii 个请求,为 00 表示不选第 ii 个请求。我们可以枚举 [0,2^m-1][0,2
m
−1] 范围内的所有 \textit{mask}mask,对于每个 \textit{mask}mask,依次枚举其每一位,判断是否为 11,并使用与方法一相同的数组 \textit{delta}delta 以及变量 \textit{cnt}cnt 进行统计,在满足要求时更新答案。
Python3C++JavaC#GolangCJavaScript
class Solution:
def maximumRequests(self, n: int, requests: List[List[int]]) -> int:
ans = 0
for mask in range(1 << len(requests)):
cnt = mask.bit_count()
if cnt <= ans:
continue
delta = [0] * n
for i, (x, y) in enumerate(requests):
if mask & (1 << i):
delta[x] += 1
delta[y] -= 1
if all(x == 0 for x in delta):
ans = cnt
return ans
复杂度分析
时间复杂度:O(2^m \times n)O(2
m
×n),其中 mm 是数组 \textit{requests}requests 的长度,即请求的数量。从 mm 个请求中任意选择请求的方案数为 2^m2
m
,对于每一种方案,我们需要 O(n)O(n) 的时间判断其是否满足要求。
空间复杂度:O(n)O(n)。数组 \textit{delta}delta 需要 O(n)O(n) 的空间。

浙公网安备 33010602011771号