運行要求
運行時間限制: 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的方法。
※ 另外,我會在個人微信我的訂閱號上推出一些文章,歡迎關注