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 秒的时间限制),她的优点是简单明了,但该算法肯定不是最优的。如果将问题的规模扩大,或者时间限制要求更严格的话,就需要寻找更好的算法了。