Timus 1152. The False Mirrors

Timus 1152. The False Mirrors 说述消灭怪物的故事,要求计算出故事中主角受到的最小伤害。

1152. The False Mirrors

Time Limit: 2.0 second
Memory Limit: 16 MB

Background

We wandered in the labyrinth for twenty minutes before finally entering the large hall. The walls were covered by mirrors here as well. Under the ceiling hung small balconies where monsters stood. I had never seen this kind before. They had big bulging eyes, long hands firmly holding riffles and scaly, human-like bodies. The guards fired at me from the balconies, I shot back using my BFG-9000. The shot shattered three mirrors filling the room with silvery smoke. Bullets drummed against my body-armor knocking me down to the floor. Falling down I let go a shot, and got up as fast as I fell down by rotating on my back, like I did in my youth while break dancing, all this while shooting three more times. Three mirrors, three mirrors, three mirrors…
Sergey Lukjanenko, "The Labyrinth of Reflections"

Problem

BFG-9000 destroys three adjacent balconies per one shoot. ( N-th balcony is adjacent to the first one). After the shoot the survival monsters inflict damage to Leonid (main hero of the novel) — one unit per monster. Further follows new shoot and so on until all monsters will perish. It is required to define the minimum amount of damage, which can take Leonid.

Input

The first string of input contains integer N, аmount of balconies, on which monsters have taken a circular defense. 3 ≤ N ≤ 20. The second string contains N integers, amount of monsters on each balcony (not less than 1 and no more than 100 on each).

Output

Output file contains one integer, minimum amount of damage.

Sample

inputoutput
7
3 4 2 2 1 4 1
9
Problem Author: Eugene Bryzgalov
Problem Source: Ural Collegiate Programming Contest, April 2001, Perm, English Tour

解答如下:

 1  using  System;
 2  using  System.IO;
 3  using  System.Text.RegularExpressions;
 4 
 5  namespace  Skyiv.Ben.Timus
 6  {
 7     //   http://acm.timus.ru/problem.aspx?space=1 &num=1152
 8     class  T1152
 9    {
10       static   void  Main()
11      {
12         new  T1152().Run(Console.In, Console.Out);
13      }
14 
15       void  Run(TextReader reader, TextWriter writer)
16      {
17        reader.ReadLine();
18         string [] ss  =  Regex.Split(reader.ReadLine().Trim(),  @" \s+ " );
19         int [] a  =   new   int [ss.Length];  //  阳台上的怪物数
20         int [] m  =   new   int [ss.Length];  //  阳台被击中的次数
21         int  sum  =   0 , damage  =   0 , min  =   int .MaxValue;
22         for  ( int  i  =   0 ; i  <  a.Length; i ++ ) sum  +=  a[i]  =   int .Parse(ss[i]);
23        writer.WriteLine(GetDamage(a, m,  ref  sum,  ref  damage, min));
24      }
25 
26       int  GetDamage( int [] a,  int [] m,  ref   int  sum,  ref   int  damage,  int  min)
27      {
28         if  (sum  ==   0 return  (min  <  damage)  ?  min : damage;  //  sum: 幸存的怪物个数
29         for  ( int  i  =   0 ; i  <  a.Length; i ++ //  遍历幸存的阳台
30        {
31           if  (m[i]  !=   0 continue ;         //  m[i]: 第 i 个阳台被击中的次数
32          damage  +=  sum  =  Shoot(a, m, sum, i,  1 1 );  //  主角开枪后怪物还击
33           if  (min  >  damage) min  =  GetDamage(a, m,  ref  sum,  ref  damage, min);
34          damage  -=  sum;                    //  回溯,还原主角受到的伤害(damage)
35          sum  =  Shoot(a, m, sum, i,  - 1 0 );  //  回溯,还原阳台(m)及其上的怪物(sum)
36        }
37         return  min;  // 消灭全部怪物后主角所受到的最小伤害
38      }
39 
40       int  Shoot( int [] a,  int [] m,  int  sum,  int  i,  int  sign,  int  cnt)
41      {
42         for  ( int  j  =  i; j  <=  i  +   2 ; j ++ //  主角每枪击毁三个相邻的阳台
43           if  (cnt  ==  (m[j  %  a.Length]  +=  sign)) sum  -=  sign  *  a[j  %  a.Length];
44         return  sum;  //  幸存的怪物个数
45      }
46    }
47  }

故事中的主角周围环绕着一圈 N (3 ≤ N ≤ 20) 个阳台,每个阳台上有若干个怪物。主角每开一枪能够摧毁相邻的三个阳台,然后幸存的怪物还击,假设每个怪物每次攻击对主角的伤害都是一个单位。然后开始新一轮枪战,直到消灭所有的怪物。你的任务就是计算出主角受到的最小伤害。

该程序调用 GetDamage() 方法来计算主角所受到的伤害(第 23 行)。该方法首先判断是否还有幸存的阳台(第 28 行),如有的话就遍历幸存的阳台(第 29 行),在循环中调用 Shoot() 方法模拟主角开枪后怪物还击(第 32 行),如果这一轮枪战之后主角所受的伤害(damage)小于消灭全部怪物后主角所受到的最小伤害(min)的话(第 33 行),就递归地调用 GetDamage() 方法自身直到消灭全部怪物(第 33 行)。程序中第 34 和 35 行是 GetDamage() 方法递归调用返回后的回溯,还原主角受到的伤害(damage)和阳台(m)及其上的怪物(sum),以便循环进入下一轮枪战。

下图是在程序的第 27 行之后 ( GetDamage() 方法的入口点 ) 和第 33 行之后 ( GetDamage() 方法递归调用后的返回点 ) 插入适当的调试语句后,经整理后得到的,显示了程序的运行情况。

这个程序的 C++ 语言版本如下:

 1  #include  < iostream >
 2 
 3  int  n, a[ 20 ], m[ 20 ];
 4 
 5  int  Shoot( int  a[],  int  m[],  int  sum,  int  i,  int  sign,  int  cnt)
 6  {
 7     for  ( int  j  =  i; j  <=  i  +   2 ; j ++ //  主角每枪击毁三个相邻的阳台
 8       if  (cnt  ==  (m[j  %  n]  +=  sign)) sum  -=  sign  *  a[j  %  n];
 9     return  sum;  //  幸存的怪物个数
10  }
11 
12  int  GetDamage( int  a[],  int  m[],  int &  sum,  int &  damage,  int  min)
13  {
14     if  (sum  ==   0 return  (min  <  damage)  ?  min : damage;  //  sum: 幸存的怪物个数
15     for  ( int  i  =   0 ; i  <  n; i ++ //  遍历幸存的阳台
16    {
17       if  (m[i]  !=   0 continue ;         //  m[i]: 第 i 个阳台被击中的次数
18      damage  +=  sum  =  Shoot(a, m, sum, i,  1 1 );  //  主角开枪后怪物还击
19       if  (min  >  damage) min  =  GetDamage(a, m, sum, damage, min);
20      damage  -=  sum;                     //  回溯,还原主角受到的伤害(damage)
21      sum  =  Shoot(a, m, sum, i,  - 1 0 );  //  回溯,还原阳台(m)及其上的怪物(sum)
22    }
23     return  min;  //  消灭全部怪物后主角所受到的最小伤害
24  }
25 
26  int  main()
27  {
28    std::cin  >>  n;
29     int  sum  =   0 , damage  =   0 , min  =  INT_MAX;
30     for  ( int  i  =   0 ; i  <  n; i ++ )
31    {
32      std::cin  >>  a[i];
33      sum  +=  a[i];
34    }
35    std::cout  <<  GetDamage(a, m, sum, damage, min)  <<  std::endl;
36  }

本程序的运行时间是: C#: 0.39 秒,C++: 0.343 秒:

但这道题最好的运行时间是 0.001 秒:

有谁知道更好的算法吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值