1005. Stone pile
Time Limit: 2.0 second
Memory Limit: 16 MB
Input
Output
Sample
input | output |
---|---|
5 5 8 13 27 14 |
3 |
解答如下:
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 秒的时间限制),她的优点是简单明了,但该算法肯定不是最优的。如果将问题的规模扩大,或者时间限制要求更严格的话,就需要寻找更好的算法了。