运行要求
运行时间限制: 2sec
内存限制: 1024MB
原文连接微信
题目
你有N根竹竿子,这N根竹竿子的长度依次为l1,l2,l3..lN(单位是厘米)
你的任务是,从N根竹竿子里面选择一些竹竿子(所有选择也能够),用这些选出来的竹竿子,制做长度为A,B,C的3根竹竿子。为了完成这项任务,赋予你3种魔法。你能够任意使用这三种魔法,使用次数任意。app
为了完成你的任务,你至少须要消耗多少MP?spa
输入前提条件命令行
输入
输入都以如下标准从命令行输入3d
N A B C l1 l2 l3 . . . lN
输出code
输出须要的最少的魔法值
例1
输入blog
5 100 90 80 98 40 30 21 80
输出内存
23
从5根长度分别是98,40,30,21,80的竹竿子里制做长度为100,90,80的3根竹竿子
咱们已经有长度为80的竹竿子,长度为90,100的竹竿子用下面的魔法获得get
例2
输入input
8 100 90 80 100 100 90 90 90 80 80 80
输出
0
已经准备好的竹竿子里面已经含有任务须要的竹竿子的话,咱们没必要使用魔法。
例3
输入
8 1000 800 100 300 333 400 444 500 555 600 666
输出
243
读懂题目
用一个数列ARR,里面有N个数。用这N个数,进行+1,-1,两两相加的方法,拼凑A,B,C。求最少的代价的方法。
+1,-1的代价是1
两两相加的方法的代价是10
解题思路
这一题咋一看,怎么办啊。合成魔法也就是拼接,貌似能够抽象成排列组合的问题。可是延长魔法(+1),缩短魔法(-1)貌似很差抽象成数学问题。
1根竹竿子,只能用在A,B,C的其中一个上。若是一根竹竿子想用在A上,又用在B上是不可能的,由于没有分解魔法…………^^
这样想的话,每一根竹竿子的归属有属于A,属于B,属于C,3种归属,而且每一根竹竿子只有一个归属
等一下,还有一种状况就是竹竿子没有被使用。由于题目条件没有说非得所有使用,也就是存在没有被使用的竹竿子的可能性。
所以每一根竹竿子的归属有属于A,属于B,属于C,没有被使用,4种归属
那么N个竹竿子,全部的状况考虑进来的话,应该有4的N次方种状况。咱们看一看条件,这里N最大是8。因此最多的状况是4的8次方,65536种状况。O(N)的复杂度的话,时间上是来得及。
如何遍历4的N次方的全部状况,这里咱们用到改进版的比特运算
那么每一种状况的MP如何求到呢。好比N=6,有6根竹竿子。
第1,2,3根竹竿子用来制做A,
4,5用来制做B,
6用来制做C
制做A所须要的MP是2次合成,而后A的长度-(1,2,3)的长度的和的绝对值
制做B所须要的MP是1次合成,而后A的长度-(4,5)的长度的和的绝对值
制做C所须要的MP是0次合成,而后A的长度-(6)的长度的和的绝对值
这一点细想就能知道
1,2,3都用开制做A的状况下,延长魔法对1使用或是对2使用,能够看做最终对合成后的竹竿子使用。
因此咱们先使用合成魔法拼接,而后再考虑用延长或者缩短魔法。
A,B,C必需要有原材料,若是出现A,B,C没有原材料的状况,该状况不容许考虑
代码
比特运算解法
import math N,A,B,C = map(int,input().split()) ARR = [] for i in range(N): ARR.append(int(input())) def calculate(n, arr, a, b, c): result = [] for i in range(4 ** n): materialA = set() materialB = set() materialC = set() materialNone = set() for j in range(n): s = (i >> 2 * j & 1) t = (i >> (2 * j + 1) & 1) if (s == 0) and (t == 0): materialA.add(j) if (s == 1) and (t == 0): materialB.add(j) if (s == 0) and (t == 1): materialC.add(j) if (s == 1) and (t == 1): materialNone.add(j) ok, mp = judge(n, arr, a, b, c, materialA, materialB, materialC, materialNone) if ok: result.append(mp) print(int(min(result))) def judge(n, arr, a, b, c, materialA, materialB, materialC, materialNone): if materialNone == n: return False, -1 if len(materialA) == 0: return False, -1 if len(materialB) == 0: return False, -1 if len(materialC) == 0: return False, -1 mpA = 0 a = a - calculateResult(arr,materialA) mpA += math.fabs(a) if len(materialA) > 1: mpA += 10 * (len(materialA) - 1) mpB = 0 b = b - calculateResult(arr,materialB) mpB += math.fabs(b) if len(materialB) > 1: mpB += 10 * (len(materialB) - 1) mpC = 0 c = c - calculateResult(arr,materialC) mpC += math.fabs(c) if len(materialC) > 1: mpC += 10 * (len(materialC) - 1) return True,mpA+mpB+mpC def calculateResult(arr,material): result = 0 for m in material: result = result + arr[m] return result calculate(N, ARR, A, B, C)
dfs解法
import math N, A, B, C = map(int, input().split()) ARR = [] for i in range(N): ARR.append(int(input())) result = [] def dfs(deep, crr): if deep == N: ok, res = calculate(crr) if ok: result.append(int(res)) else: for i in range(4): crr[deep] = i dfs(deep + 1, crr) def calculate(crr): sA = [] sB = [] sC = [] sN = [] for index, cr in enumerate(crr): if cr == 0: sN.append(ARR[index]) if cr == 1: sA.append(ARR[index]) if cr == 2: sB.append(ARR[index]) if cr == 3: sC.append(ARR[index]) if len(sA) == 0: return False, -1 if len(sB) == 0: return False, -1 if len(sC) == 0: return False, -1 s1 = (len(sA) - 1) * 10 + math.fabs(sum(sA) - A) s2 = (len(sB) - 1) * 10 + math.fabs(sum(sB) - B) s3 = (len(sC) - 1) * 10 + math.fabs(sum(sC) - C) return True, s1 + s2 + s3 dfs(0, [0 for i in range(N)]) print(min(result))
总结
这里考察了如何把魔法问题抽象成排列组合的数学问题的思惟
另外对于如何遍历4的N次方的状况的方法也进行了考察
遍历的方法这里用到了比特运算。还有DFS的方法。
※ 另外,我会在个人微信我的订阅号上推出一些文章,欢迎关注