The third simulation game of the 12th Blue Bridge Cup-ABC (Binary-Dynamic Programming)

1. Problem description:

Time limit: 3.0s Memory limit: 512.0MB Total score for this question: 25 points The
grocery store owner has a total of N items, and each item has one or more of the three attributes of ABC. Buying an item from the grocery store owner needs to pay a corresponding price. Now you need to figure out how to purchase items so that each of the three attributes of ABC appears in at least one item purchased, and the total cost paid is the smallest.
[Input format] The
first line of input contains an integer N.
The following N lines, each line contains an integer C and a string containing only "ABC", representing the cost of purchasing the item and its attributes.
[Output format]
Output an integer, which represents the minimum cost. If the three attributes of ABC are missing anyway, -1 is output.
[Sample input]
5
10 A
9 BC
11 CA
4 A
5 B
[Sample output]
13
[Evaluation use case scale and conventions]
For 50% of evaluation use cases, 1 <= N <= 20
For all evaluation use cases, 1 < = N <= 1000, 1 <= C <= 100000

2. Thinking analysis:

① At the beginning, I thought of using the recursive method to try all possible splicing schemes (for the current string, you can choose whether to have two parallel states or not, two recursive methods can solve it), but because the amount of data is 10^5 Overtime, I feel that this problem should be solved by dynamic programming (optimization under the condition of violent enumeration), but at the beginning I did not find a better way to represent the three attributes of ABC. I saw one on csdn The method of using binary to represent the three attributes of ABC, I feel that this old man writes very well, the idea is to use the binary + dynamic programming method, where 4/2/1 in the binary represents the three attributes of CBA, so You can map the three attributes of ABC to the subscript. Because you are using the python language, you can declare a dp list of length 8 (equivalent to an array of java or c, c++), dp[i] means having The minimum cost of the attribute of i. A number i represents the attribute of the current item. After the meaning of dp[i] is determined, the next steps are easy to handle. For the attributes of the current item, try to add it to other items. (Loop through dp[1]~dp[7]) to see if the attribute and value have changed. If you find that the value that can be formed is smaller, then update the value corresponding to the position after adding the attribute. The dp state transition equation is not difficult. Think of dp[v | j] = c + dp[j] (c + dp[k] <dp[v | k]), c represents the value of the current input item, v represents the attribute of the current input item, v | j means try to add the current attribute to the position with j representative attribute to see if it can constitute a lower cost.

② When we encounter this problem that can use violent enumeration, we need to think about dynamic programming when the amount of data is large, and see how we can make further optimizations, and make it clear that the previous state and the current state may pass What kind of derivation method is used in many cases is the violence of some combination problems. There may be multiple combinations to get the current state. My goal is to find the optimal state through a loop, and the state transition is actually A very critical step, a reference blog for the big guys

3. The code is as follows:

import sys
if __name__ == '__main__':
    dp = [sys.maxsize] * 8
    N = int(input())
    for i in range(N):
        # split函数的返回值就是一个列表
        cur = input().split()
        c = int(cur[0])
        v = 0
        # v记录当前物品具有的属性
        for j in cur[1]:
            # 左移这么多位表示在xxx对应的二进制位上将置为1表示存在这个属性,
            v |= 1 << (ord(j) - ord("A"))
        # 上面的循环结束之后v表示的就是当前输入物品具有的所有属性
        # 长度为8的循环是为了尝试将当前的输入物品属性添加到之前的位置看是否能够构成代价更小的
        for k in range(1, 8):
            # v & k != v表示之前已经具有所有的属性这个时候添加进来一点贡献都没有
            # c + dp[k] < dp[v | k]其中v | k表示将当前的物品添加到k这个位置对应的属性中看是否构成价值更小
            # 或运算的意思是添加当前输入物品的属性到之前的物品属性中
            if v & k != v and dp[k] != sys.maxsize and c + dp[k] < dp[v | k]:
                dp[v | k] = c + dp[k]
        # 取出dp[v]与c中的最小值的那个
        dp[v] = min(dp[v], c)
    # 输出最后一个元素表示具有三种属性的物品花费的最小价值
    print(dp[7] if dp[7] != sys.maxsize else -1)

 

Guess you like

Origin blog.csdn.net/qq_39445165/article/details/115260347