24位掩码和30个掩码_高级ds位掩码和dp的问题

24位掩码和30个掩码

In this post we are going to look at one of the ‘simplest’ Dynamic Programming variation — Bitmasking. When I say ‘simplest’ I mean that ‘Bitmasking + DP’ problems are easy to identify and also most bit-masking problems have a more or less similar approach.

在本文中,我们将介绍“最简单的”动态编程变体之一-位掩码。 当我说“最简单”时,我的意思是“位掩码+ DP”问题很容易识别,而且大多数位掩码问题都具有或多或少相似的方法。

Some of the common traits of Bitmasking problems are:

Bitmasking问题的一些共同特征是:

  1. Path finding problems — Enumerate all possible paths or paths based on certain conditions.

    路径查找问题-列举所有可能的路径或基于某些条件的路径。
  2. For a given input array A, depending in which order we go through the elements of the array A our objective function will change.

    对于给定的输入数组A,根据我们经过数组A元素的顺序,我们的目标函数将发生变化。
  3. They require exponential runtime.

    它们需要指数运行时间。
  4. For folks into competitive programming will understand that problems with constraint on N (≤ 20) (i.e. size of array) hints towards bitmasking + DP.

    对于参加竞争性编程的人们来说,他们会明白约束N(≤20)(即数组大小)的问题暗示了位掩码+ DP。

I will not go into the details of bit-manipulation (which will be a topic of discussion later). For understanding bit-manipulation operations, I would refer to this stackoverflow forum.

我将不讨论位操作的细节(稍后将讨论这个话题)。 为了理解位操作,我将参考这个stackoverflow论坛。

https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit

https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit

We will look at 5 problems to understand why these needs Bitmasking + DP approach to solve.

我们将看5个问题,以了解为什么这些问题需要使用Bitmasking + DP方法来解决。

Problem 1

问题1

There is a new food delivery startup in town. For simplicity, assume that there are N delivery executives and N orders. Also we have estimated how much it would cost the startup if delivery executive ‘i’ delivers the order ‘j’. This considers all factors such as distance, traffic, customer priority, food value etc.

镇上有一家新的外卖公司。 为简单起见,假设有N个交货主管和N个订单。 我们还估计了如果交付执行官“ i”交付订单“ j”会给启动公司带来多少费用。 这考虑了所有因素,例如距离,交通,客户优先级,食品价值等。

Given a NxN cost matrix, we need to assign each order to an executive in such a way that the total cost to the startup is minimum.

给定一个NxN的成本矩阵,我们需要将每个订单分配给执行人员,以使启动的总成本最小。

Note that each order is to be allotted to a single executive, and each executive will be allotted only one order.

请注意,每个命令都将分配给一个主管,而每个主管将仅分配一个命令。

The brute force approach can be solved using recursion:

蛮力方法可以使用递归来解决:

The run-time complexity is O(N!) (1st person there are N choices, for each choice the 1st person makes, 2nd person can make N-1 choices and so on).

运行时复杂度为O(N!)(第一个人有N个选择,第一个人做出的每个选择,第二个人可以做出N-1个选择,依此类推)。

We can do better than this by realising that when we have assigned tasks to the first i persons, the cost of assignment of the remaining tasks to the remaining persons is independent of the task assignments made to the first ‘i’ persons. Thus we can cache the results.

我们可以意识到,当我们将任务分配给第一个i人时,可以做得更好,剩下的任务分配给其余人的成本与分配给第一个“ i”人的任务无关。 这样我们就可以缓存结果。

We can use a bit-vector of size N, to hold the assigned tasks. Then we can use a cache. For e.g. if N=5, then assigned = [1,0,1,1,0], implies that tasks 0, 2 and 3 has been assigned to the first 3 persons.

我们可以使用大小为N的位向量来保存分配的任务。 然后我们可以使用缓存。 例如,如果N = 5,则分配= [1,0,1,1,0],表示任务0、2和3已分配给前3个人。

The modified code is as follows:

修改后的代码如下:

The run-time of the above code is O(N*2^N).

上面的代码的运行时间为O(N * 2 ^ N)。

Overall space complexity is O(N*2^N), due to the in-memory ‘cache’ variable. Each key is of length N and there are 2^N possible keys.

由于内存中的“ cache”变量,总体空间复杂度为O(N * 2 ^ N)。 每个密钥的长度为N,并且可能有2 ^ N个密钥。

We can avoid the bit vector by using bit-operations. Since the binary representation of the bit vector denotes a decimal integer, we can alternatively use an integer for ‘assigned’ variable. Setting and un-setting of bits of the integer can be done using bit-wise operators.

我们可以通过使用位操作来避免位向量。 由于位向量的二进制表示形式是十进制整数,因此我们可以选择对“ assigned”变量使用整数。 可以使用按位运算符来设置和取消设置整数的位。

For e.g. if N=5, then assigned = 13, implies that tasks 0, 2 and 3 has been assigned because the binary representation for integer 13 is ‘01101’.

例如,如果N = 5,则分配= 13,这意味着任务0、2和3已分配,因为整数13的二进制表示为'01101'。

Note that we have reversed the order of bits in this notation because it is easier to work with bit manipulation starting from the right end. Thus 0-th bit is set implies that the last bit is set and so on.

请注意,我们以这种表示法颠倒了位的顺序,因为从右端开始更容易进行位操作。 因此,设置第0位意味着设置了最后一位,依此类推。

(https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit)

( https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit )

The same code when written using bitwise operators:

使用按位运算符编写时,相同的代码:

The space complexity is now O(2^N).

现在,空间复杂度为O(2 ^ N)。

‘(k & 1<<j)’ returns 0 if j-th bit is not set in integer k else non-zero. (j is 0-indexed)

如果未在整数k中设置第j位,则'(k&1 << j)'返回0,否则为非零。 (j为0索引)

To set the j-th bit of an integer k do ‘k |= (1 << j)’ and to unset do ‘k &= ~(1 << j)’

要设置整数k的第j位,请执行'k | =(1 << j)',而要取消设置请执行'k&=〜(1 << j)'

The properties of the problem, if we observe carefully, satisfy all the Bitmasking problem traits:

如果我们仔细观察,问题的性质将满足所有Bitmasking问题特征:

  1. Depending in which order we assign the ‘orders’ to the executives, the overall cost will change.

    根据我们将“订单”分配给高管的顺序,总成本将发生变化。
  2. Since we need to evaluate all possible ordering of ‘orders’, the total number of orderings is N!. Thus require exponential runtime.

    由于我们需要评估“订单”的所有可能排序,因此订单总数为N!。 因此需要指数运行时间。

We can also define a non-recursive solution as follows:

我们还可以如下定义非递归解决方案:

f[k] denotes the minimum cost of assigning a subset of M tasks (represented by the integer ‘k’) to the first n persons (where n = number of bits set in k).

f [k]表示将M个任务的子集(用整数“ k”表示)分配给前n个人员(其中n = k中设置的位数)的最小成本。

For an 8x8 cost matrix, the average time taken by the 1st approach (non-cached) is 0.11 seconds whereas average time taken by the last approach is 0.00083 seconds.

对于8x8成本矩阵,第一种方法(非缓存)所花费的平均时间为0.11秒,而最后一种方法所花费的平均时间为0.00083秒。

Problem 2

问题2

You are given a list A of N integers. Here, N is an even number. These integers must be distributed into N/2 pairs and the power of each of the pairs is added.

您将得到一个由N个整数组成的列表A。 在此,N是偶数。 这些整数必须被分配为N / 2对,并且每对的幂加在一起。

The power of a pair P(i, j) consisting of the i-th and j-th number is defined as bitwise XOR of the two numbers A[i] and A[j], that is A[i] ^ A[j] where 1 < i < N, 1 < j < N and i != j.

将由第i和第j个数组成的对P(i,j)的幂定义为两个数A [i]和A [j]的按位XOR,即A [i] ^ A [ j],其中1 <i <N,1 <j <N并且i!= j。

Write a program to determine the minimum and the maximum possible sum of the N/2 pairs.

编写程序以确定N / 2对的最小和最大可能和。

Again this problem has the following characteristics:

同样,此问题具有以下特征:

  1. Assuming that the array A is the list of N integers, we need to assign each integer to only a single pair.

    假设数组A是N个整数的列表,我们需要将每个整数仅分配给一对。
  2. Depending in which order we assign the integers to the pairs, the total sum would change.

    根据我们将整数分配给对的顺序,总和将发生变化。
  3. We need to evaluate all possible pairings. The number of possible pairings is N!/((N/2)!*2^(N/2)). Which is still exponential in N.

    我们需要评估所有可能的配对。 可能的配对数为N!/((N / 2)!* 2 ^(N / 2))。 在N中仍是指数的。

Brute force solution is to go through all possible assignment of integers to the pairs which can be easily accomplished using recursion. But will skip that as it is trivial.

蛮力解决方案是对整数进行所有可能的分配,这可以使用递归轻松实现。 但由于它是微不足道的,所以将跳过它。

Below is the Python solution with bitmasking and DP:

以下是具有位屏蔽和DP的Python解决方案:

As before we let the assigned integers be represented using N bits. Thus the assigned integers can be represented using another integer between 0 and 2^N-1.

如前所述,我们让分配的整数使用N位表示。 因此,可以使用0到2 ^ N-1之间的另一个整数表示分配的整数。

For e.g. if the array is [1,2,3,4,5,6], then the assignment ‘101011’=43 implies that the numbers at indices 0, 1, 3 and 5 has been assigned (indexing starts from end) and they are part of 2 groups:

例如,如果数组为[1,2,3,4,5,6],则分配'101011'= 43表示已分配了索引0、1、3和5的数字(索引从末尾开始)它们是2组的一部分:

The 2 groups can be (1,2)(4,6) or (1,4)(2,6) or (1,6)(2,4).

这两个组可以是(1,2)(4,6)或(1,4)(2,6)或(1,6)(2,4)。

Each time pick 2 integers from the set bits, and using DP find the minimum of the remaining bits and add the XOR of the 2 integers. Note that we must only pick integers when the number of assigned bits is even.

每次从设置的位中选择2个整数,然后使用DP查找剩余位数的最小值,然后将2个整数的XOR相加。 请注意,只有在分配的位数为偶数时,才能选择整数。

Time complexity of the above approach is O(N²*2^N). Space complexity is O(2^N).

上述方法的时间复杂度是O(N 2 * 2 ^ N)。 空间复杂度为O(2 ^ N)。

Problem 3

问题3

There are n people and 40 types of hats labeled from 1 to 40.

n个人和40种帽子,标记为1到40。

Given a list of list of integers hats, where hats[i] is a list of all hats preferred by the i-th person.

给定一个整数hats列表,其中hats[i]是第i-th个人首选的所有hats的列表。

Return the number of ways that the n people wear different hats to each other.

返回n人互相戴不同帽子的方式数。

This is similar to the order assignment problem, only difference is that the number of executives may not be equal to the number of orders (which is more realistic). Also the problem asks for number of ways of assignment instead of finding minimum cost.

这类似于订单分配问题,唯一的区别是高管人数可能不等于订单数量(这更现实)。 问题还要求分配方式的数量而不是找到最低成本。

The problem satisfies the following traits:

该问题满足以下特征:

  1. If we assume that the array A is the list of people then we must assign a single hat to each people depending on their preferences.

    如果我们假设数组A是人员列表,那么我们必须根据每个人的偏好为他们分配一个帽子。
  2. Depending on which hat is assigned to which people, we would have different number of ways of assigning hats.

    根据分配给哪个人的帽子,我们将有不同数量的帽子分配方式。
  3. Total number of assignments is exponential in N (number of people). Then the number of possibilities is approximately ‘M chooses N’ where M is the number of hats.

    作业总数是N(人数)的指数。 那么可能性的数量大约是“ M选择N”,其中M是帽子的数量。
  4. For a subset of K people, the number of ways of assigning hats numbered 1 to H can be found by assuming that the i-th person selects the H-th hat (if he has in its preference) and the remaining K-1 people selects from hats numbered 1 to H-1.

    对于K个人的子集,可以通过假设第i个人选择第H个帽子(如果他愿意)选择剩余的K-1个人,从而找到将帽子1分配给H的方式数量。从1到H-1的帽子中选择。

The problem can be solved using recursion. But that would be trivial.

该问题可以使用递归来解决。 但这将是微不足道的。

Instead we show a python solution using bitmasking + DP approach:

相反,我们展示了使用位屏蔽+ DP方法的python解决方案:

f[k][h] — denotes the number of ways of assigning hats numbered 1 to h to the set of people represented by the integer ‘k’.

f [k] [h] —表示将1到h的帽子分配给由整数“ k”表示的一组人的方式的数量。

Thus if N=5, k=13 and h=8, then the binary representation for 13 = ‘01101’, denotes that hats 1 to 8 has been distributed to the 0-th, 3-rd and 4-th people.

因此,如果N = 5,k = 13,h = 8,则13 ='01101'的二进制表示表示帽子1至8已分发给第0、3和4个人。

f[k][h] can be computed by finding the people whose preferences has the h-th hat then using DP adding the number of ways f[k & ~(1<<i)][h-1] i.e. number of ways of assigning hats 1 to h-1 to all people except the i-th person.

f [k] [h]可以通过找到其偏好具有第h个帽子的人来计算,然后使用DP添加方法f [k&〜(1 << i)] [h-1]的数量,即将第1到1个帽子分配给除第i个人以外的所有人的方法。

Problem 4

问题4

Hamiltonian Path is a path in a directed or undirected graph that visits each vertex exactly once. Given an undirected graph, check whether it contains a Hamiltonian Path or not.

哈密​​顿路径是有向或无向图中的一条路径,该路径恰好访问每个顶点一次。 给定无向图,请检查其是否包含哈密顿路径。

This looks like a simple case of depth first search. But with DFS we need to traverse all possible paths and then check if at-least one path has all the N vertices. Alternatively we can list all possible permutations of the vertices and check if there is any permutation where all adjacent vertices has an edge between them.

这看起来像是深度优先搜索的简单情况。 但是,使用DFS,我们需要遍历所有可能的路径,然后检查至少一条路径是否具有所有N个顶点。 或者,我们可以列出所有可能的顶点排列,并检查在所有相邻顶点之间是否有边的情况下是否存在任何排列。

Complexity of above is O(N!) because we need to traverse all possible paths.

上面的复杂度是O(N!),因为我们需要遍历所有可能的路径。

The problem has the following properties:

该问题具有以下属性:

  1. We need to visit all vertices exactly once.

    我们需要一次访问所有顶点。
  2. Number of vertices covered depends on the order in which we visit them due to the adjacency matrix.

    由于邻接矩阵的关系,覆盖的顶点数量取决于我们访问顶点的顺序。
  3. Total number possible paths is O(N!) which is exponential in N.

    可能的路径总数为O(N!),以N为指数。
  4. There exists a Hamiltonian path of K vertices if there is a vertex i such that if j is the end vertex of a Hamiltonian path of the remaining K-1 vertices (excluding i) then there is an edge between i and j.

    如果存在一个顶点i,则存在K个顶点的哈密顿路径,如果j是其余K-1个顶点(不包括i)的哈密顿路径的终点,则i和j之间会有一条边。

Which makes bitmasking + DP as a potential approach for solving this problem.

这使得位屏蔽+ DP成为解决此问题的潜在方法。

The bitmasking + DP python solution is as follows:

位掩码+ DP python解决方案如下:

Let f[k][i] = ‘True’ if there is a Hamiltonian path with the vertices represented by the bit vector ‘k’ ending with vertex i else ‘False’.

令f [k] [i] ='True',如果存在哈密顿路径,其顶点由位向量'k'表示,顶点为顶点,否则为'False'。

We encode the vertices using bits. Then for a set of assigned vertices, we select a vertex i and then for each end vertex j, f[k][i] is True only if f[k & ~(1 <<i)][j] (assigned vertices excluding i, ending with vertex j) is True and there is an edge between i and j.

我们使用位对顶点进行编码。 然后,对于一组指定的顶点,我们选择一个顶点i,然后对于每个端点j,仅当f [k&〜(1 << i)] [j](指定的顶点)时,f [k] [i]为True不包括i,以顶点j)结尾的值为True,并且i和j之间有一条边。

Time complexity of the above is O(N²*2^N) and space complexity is O(N*2^N).

上面的时间复杂度为O(N²* 2 ^ N),空间复杂度为O(N * 2 ^ N)。

Problem 5

问题5

You are given a bunch of sticks. For each stick, its two ends are labelled with two numbers (1–6, possibly same).

给你一堆木棍。 对于每个摇杆,其两端都标有两个数字(1-6,可能相同)。

You can connect two stick A and B, if and only if one of numbers of stick A is the same as one of the numbers of stick B. For example, a stick with [1,5] can be connected with a stick with [1,4] by connecting the two ends labelled as 1. In this case, these two sticks will become one with longer length, and its two ends now becomes [4,5]. Assume for each given stick, its length is 1.

当且仅当一根棒A的数量与一根棒B的数量相同时,才能连接两个棒A和B。例如,具有[1,5]的棒可以与带有[1,4]通过连接标为1的两端来连接[ [1,4] 。在这种情况下,这两根木棍将变成一个更长的一根,现在其两端变成[4,5] 。 假设每个给定的棒的长度为1。

Return the length of longest stick that can be formed using the given sticks.

返回可以使用给定棒形成的最长棒的长度。

The problem is similar to the Hamiltonian path problem seen above as in we need to do DFS to find the solution, only difference is that instead of finding a Hamiltonian path, we need to find the longest path.

这个问题与上面看到的哈密顿路径问题相似,因为我们需要做DFS来找到解决方案,唯一的区别是,除了找到哈密顿路径之外,我们还需要找到最长的路径。

This can be done in brute force way by recursion (DFS) but that would not be interesting enough !!! By now we must have got the clue how this problem can be solved using bitmasking and DP.

可以通过递归(DFS)以暴力方式完成此操作,但这还不够有趣! 到目前为止,我们必须已经有了使用位掩码和DP解决此问题的线索。

Below is the python code:

以下是python代码:

f[k][i][0] = max length stick formed with sticks represented by integer k ending with the i-th stick.

f [k] [i] [0] =由长度为i的整数k表示的棒形成的最大长度棒。

f[k][i][1] = number on the end-face of the final stick.

f [k] [i] [1] =最终杆的端面上的数字。

The recursive relation and the remaining code is quite self explanatory if you have followed the earlier problems carefully. As with the Hamiltonian path problem, time complexity is again O(N²*2^N).

如果您仔细地遵循了先前的问题,那么递归关系和其余代码将很容易说明。 与汉密尔顿路径问题一样,时间复杂度再次为O(N²* 2 ^ N)。

This ends our discussion on Bitmasking + DP. This is one of the few common DP strategies asked quite frequently in online competitive programming and online programming assessments.

这样就结束了我们有关位屏蔽+ DP的讨论。 这是在线竞争性编程和在线编程评估中经常问到的少数几种常见的DP策略之一。

翻译自: https://medium.com/swlh/problems-with-advanced-ds-bitmasking-and-dp-ce43cc6c26fb

24位掩码和30个掩码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值