Problem
You have a number of stones with known weights w 1, …, wn. Write a program that will rearrange the stones into two piles such that weight difference between the piles is minimal.
Input
Input contains the number of stones n (1 ≤ n ≤ 20) and weights of the stones w 1, …, wn (integers, 1 ≤ wi ≤ 100000) delimited by white spaces.
Output
Your program should output a number representing the minimal possible weight difference between stone piles.
Example
input | output |
---|---|
5 5 8 13 27 14 |
3 |
题目大意
给出一坨重量不定的石头,将其分成两份使得其重量差值最小。
题目解读
石头总数很少,重量偏大(也不是十分大)。
算法
设所有石头总重量为 S,要使两份石头重量差值最小,换句话说就是让每一份石头的重量都尽量接近 S / 2。
考虑一个容量为 ?S / 2? 的背包,用石头把这个背包尽量填满,此时将所有石头以是否在背包中为标准,分成两堆,这两堆石头重量差值即为题目所求解。
直接套用 0-1 背包,f[i] = max{f[i - w[j]] + w[j]},时间复杂度 O(nS)。
代码
1 n = int(input()) 2 w = input().split() 3 for i in range(n): 4 w[i] = int(w[i]) 5 s = sum(w) 6 m = s - s // 2 7 f = [0 for i in range(m + 1)] 8 for i in range(n): 9 for j in range(m, w[i] - 1, -1): 10 f[j] = max(f[j], f[j - w[i]] + w[i]) 11 print(abs(s - f[m] * 2))
算法 2
本来想用背包直接偷鸡,实际上上述算法也是足够快的,但无奈 Python 速度实在无法与 C++ 相比。
老老实实改用搜索,时间复杂度 O(2n),保险起见排了个序加了个可行性剪枝。
代码 2
n = int(input()) w = input().split() def dfs(now, size): if ((now == n) or (size < w[now])): return size; return min(dfs(now + 1, size - w[now]), dfs(now + 1, size)) for i in range(n): w[i] = int(w[i]) w.sort() s = sum(w) m = s - s // 2 print(abs(s - (m - dfs(0, m)) * 2))
代码解读
注意:以下内容完全根据笔者自己对 Python 3 的理解胡说八道。
sum():求和函数,返回列表所有元素的和。
max():最大值函数,返回若干个数(或列表)中最大的元素。
abs():绝对值函数,返回一个数的绝对值。
def:定义函数(?)。
min():最小值函数,返回若干个数(或列表)中最小的元素。
sort():排序函数,默认将列表元素按升序排序。