Timus 1005. Stone pile

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

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值