angryA (USACO 2016 JAN Bronze)

21 篇文章 0 订阅
9 篇文章 0 订阅

在正文之前先说点题外话。

寒假以来,由于自身的种种原因,我在OI方面没有用功,既没有刷题也没有进行总结,甚至连题库和博客都没有登录过,在此要认真检讨。而且今天的创新班也让我发现自己开始出现的一些弊病:心态方面,方法和习惯等等。为什么自己开始出现这些问题?如何解决?还是要靠良好的心态为基础。希望新的学期里戒骄戒躁,坚持刷题和写博客,日积月累慢慢进步。毕竟身边厉害的同学和学长很多,自己没有任何借口来偷懒,没有任何理由来骄傲。

=============

【试题来源】

USACO月赛2016年1月铜牌组

【题目描述】

牛奶Bessie设计了一个游戏:“愤怒的牛奶”。游戏的原型是:有一些可爆燃的草堆分布在一条数轴的不同坐标,玩家用弹弓把一头奶牛发射到数轴上。牛奶砸到草堆上的冲击能量会引发草堆燃爆,并有可能引起附近的草堆连环燃爆。游戏的目标是玩家用一头奶牛燃爆尽可能多的草堆。
有N个草堆在数轴的不同位置,坐标为x1,x2,….,xn。如果玩家把牛发射到坐标是x的草堆上,这个草堆就会燃爆,冲击波的半径是1,距离它是1的草堆也会被燃爆。这些相邻的草堆会同时燃爆,并且冲击波的半径是2。下一步,被燃爆的草堆冲击波半径会是3。一般的,时间t燃爆的草堆,每一个的冲击波半径是t,被这些冲击波引爆的草堆在t+1时刻会产生冲击波半径是t+1,以此类推。
请计算,只用一头奶牛玩家最多可以燃爆多少草堆?

 【输入格式】

第一行:一个整数N( 1 ≤ N ≤ 100)。
下面有N行,每行一个整数:x1, x2 ,…,xn,范围在[0…1,000,000,000]

 【输出格式】

输出最大可能燃爆的草堆数。

【输入样例】

6
8
5
6
13
3
4

【输出样例】

5

【样例解释】

In this example, launching a cow onto the hay bale at position 5 will cause the bales at positions 4 and 6 to explode, each with blast radius 2. These explosions in turn cause the bales at positions 3 and 8 to explode, each with blast radius 3. However, these final explosions are not strong enough to reach the bale at position 13.

=============

看到这题,容易想到几种不同的算法,各自实现起来会有不同的特点。

而且我们还发现,本题数据范围很小,完全可以用朴素的方法实现,例如模拟。

(挺符合铜牌组题目的特点。。)

那么言归正传,就算是模拟也可以有不同的实现方式。
由于本人比较笨,为了避免各种细节处理问题,用了复杂度高达O(n^4)的算法,当然n^4只是理论上限,实际上是不会TLE的。 (这显然是在为自己懒而找借口啊。。)
具体的实现见下

#include<cstdlib>
#include<cstdio>
#include<cstring>

//定义max和min宏
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)

const int SIZE = 100 + 5 ;

int N , x[SIZE] , ans=0 , f[SIZE] ;

int work ( int ) ;

//work(n)表示以n为发射点最多可以燃爆多少草堆

int main () {

//输入数据
scanf ( "%d" , &N ) ;
for ( int i=0 ; i!=N ; ++i )
scanf ( "%d" , &x[i] ) ;

//枚举发射点,取最优解
for ( int i=0 ; i!=N ; ++i )
ans = max ( ans , work(i) ) ;
printf ( "%d\n" , ans ) ;
return 0 ;
}

int work ( int cur ) {

//f[]数组储存坐标为xi的草堆被燃爆的时间
memset ( f , -1 , sizeof f ) ; //-1表示草堆未被燃爆
f[cur] = 0 ; //选定的发射点是初始燃爆点,记作时间0
int tot=1 ; //当前被燃爆的草堆数量
for ( int t=1 ; t!=N+1 ; ++t ) { //t为当前时间
bool flag=false ; //flag表示当前时刻是否有新草堆被燃爆
for ( int i=0 ; i!=N ; ++i ) //枚举每一个草堆
if ( f[i]==-1 ) //若草堆i未被燃爆,尝试燃爆它
for ( int j=0 ; j!=N ; ++j )

//枚举一个可以燃爆它的草堆
if ( f[j]==t-1 && abs(x[i]-x[j])<=t ) {

//若草堆j是前一个时间点燃爆的且半径足够
f[i] = t ; //在时间t燃爆草堆i
++ tot ; //统计总数
flag = true ;//标记有草堆被燃爆

break ; //停止寻找可以燃爆i的j
}
if (!flag) return tot ;

//当前时间没有燃爆任何草堆,则继续进行无意义,

//tot即为以cur为初始发射点的最多燃爆数,返回它
}
return tot ; //所有草堆均被燃爆的情况
}


那么其实我的这种方法是非常麻烦,相当笨的。
模拟起来会很吃力,时间复杂度也是很高,在这里推荐王志远神犇的另一种解法,见他的 一篇题解
以上。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值