Timus 1005. Stone pile 要求将若干石头分为两堆使其重量差最小。
1005. Stone pile
Time Limit: 2.0 second
Memory Limit: 16 MB
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 (1 ≤
Wi ≤ 100000) delimited by white spaces.
Output
Your program should output a number representing the minimal possible weight difference between stone piles.
Sample
input |
output |
5 5 8 13 27 14 |
3 |
Problem Source: USU Championship 1997
解答如下:
1
using
System;
2
using
System.IO;
3
using
System.Text.RegularExpressions;
4
5
//
http://acm.timus.ru/problem.aspx?space=1
&num=1005
6
class
Acm1005
7
{
8
static
void
Main()
9
{
10
new
Acm1005().Run(Console.In, Console.Out);
11
}
12
13
void
Run(TextReader reader, TextWriter writer)
14
{
15
writer.WriteLine(GetResult(GetWeigths(reader)));
16
}
17
18
int
[] GetWeigths(TextReader reader)
19
{
20
string
[] ss
=
Regex.Split(reader.ReadToEnd().Trim(),
@"
\s+
"
);
21
int
[] weigths
=
new
int
[
int
.Parse(ss[
0
])];
22
for
(
int
i
=
0
; i
<
weigths.Length; i
++
) weigths[i]
=
int
.Parse(ss[i
+
1
]);
23
return
weigths;
24
}
25
26
int
GetResult(
int
[] weigths)
27
{
28
int
n
=
weigths.Length
-
1
;
29
int
result
=
int
.MaxValue;
30
int
[] piles
=
new
int
[
2
];
31
for
(
int
i
=
(
1
<<
n)
-
1
; i
>=
0
; i
--
)
32
{
33
piles[
0
]
=
weigths[n];
34
piles[
1
]
=
0
;
35
for
(
int
j
=
n
-
1
; j
>=
0
; j
--
) piles[(((i
>>
j)
&
1
)
==
0
)
?
1
:
0
]
+=
weigths[j];
36
int
v
=
Math.Abs(piles[
0
]
-
piles[
1
]);
37
if
(result
>
v) result
=
v;
38
}
39
return
result;
40
}
41
}
这道题是说,给你一堆石头,总数在 1 到 20 之间,每个石头的重量在 1 到 100,000 之间。要求你将这堆石头分成两堆,使这两堆石头的重量差最小,并输出这个重量差。
由于这道题目的时间限制是 2.0 秒(这个时间非常宽松了),且输入的规模不大(石头的总数不超过 20),所以我是用蛮力搜索穷举每一种可能的分配方案,找出最优的。
程序中第 26 到 40 行的 GetResult 方法的输入参数 weigths 数组记录每个石头的重量。第 29 行 result 变量就是用来记录两堆石头的重量差的,也就是我们要输出的结果。第 30 行 int 类型数组 piles 的长度为 2,它的两个元素分别代表两堆石头的重量。
程序中第 28 行将 n 设为石头总数减一,这有两重含义:首先,在第 33 行将第 n 个(也是最后一个,因为 C# 数组的下标是从 0 开始的)石头分配到第 0 堆(piles[0])中。其次,蛮力搜索需要穷举 2n 种可能的情况,这体现在第 31 行开始的循环中,变量 i 从 2n -1 开始递减到 0 以遍历这 2n 种可能的情况。
程序中第 35 行的循环根据变量 i 的值(该值代表了蛮力搜索的每一种可能的分配方案)将石头分配到两堆中,这是根据 i 的第 j 位是否为 0 来决定的,如果为 0 则分配到第 1 堆中,否则就分配到第 0 堆中。第 36 行计算这两堆石头的重量差,第 37 行用来更新最小的重量差。
这个算法仅仅是能够 Accepted 而已(这个程序的实际运行时间是 0.171 秒,没有超过 2.0 秒的时间限制),她的优点是简单明了,但该算法肯定不是最优的。如果将问题的规模扩大,或者时间限制要求更严格的话,就需要寻找更好的算法了。