USACO 2016 JAN——Angry Cows套题的解题报告

来源:互联网 发布:小米怎么看网络制式 编辑:程序博客网 时间:2024/05/21 12:08
 
【A:angry cows BRONZE】

 angryA (USACO 2016 JAN Bronze)
题目描述

牛奶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
【题意分析】

1:数据最多只有100个草堆,爆搜直接就过了。时间复杂度是O(n^2)。
2:只要不断地把爆炸的冲击波半径+1,一直加到不能再加为止(即全部炸完或冲击波的半径不够)。每次把炸到的草堆记为已炸到就可以了。
 
【程序】

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

int n,ans;
int a[110];
bool bo[110];

void f(int w,int t)
{
 int p,q;
 
 p=1;
 while( a[w] - a[w-p] <= t && a[w] - a[w-p] >=0 && w-p>0 &&bo[w-p])    //在这个冲击半径内,能引爆几个的草堆?(左边)
 {
  
  ans++; //草堆个数加 1
  bo[w-p]=0; //被引爆
  p++;
 }
 
 q=p-1;
 
 p=1;
 while( a[w+p] - a[w] <= t && a[w+p] - a[w] >=0 && w+p<=n &&bo[w+p])    //在这个冲击半径内,能引爆几个的草堆?(右边)
 {
  
  ans++; //草堆个数加 1 
  bo[w+p]=0; //被引爆
  p++;
 }
 p--;
 
 
 if(w-q>0&&q>0)
  f(w-q,t+1);//左边
 if(w+p<=n&&p>0)
  f(w+p,t+1);//右边
 
}

int main()
{
 int maxx=-0x0fffffff;
 scanf("%d",&n);
 for(int i=1;i<=n;i++)
  scanf("%d",&a[i]);
  
 sort(a+1,a+n+1);
 
 for(int i=1;i<=n;i++)
 {
    
  memset(bo,1,sizeof(bo));
  ans=1;
  
  bo[i]=0;//奶牛直接引爆
  f(i,1);
  
  maxx=max(maxx,ans);//保存最大值
 }
 
 printf("%d",maxx);
 return 0;
 
}

【B:angry cows SLIVER】
angryB (USACO 2016 JAN silver)
题目描述

牛奶Bessie设计了一个游戏:“愤怒的牛奶”。游戏的原型是:有一些可爆燃的草堆分布在一条数轴的不同坐标,玩家用弹弓把奶牛发射到数轴上。牛奶砸到数轴上的冲击波会引发附近的草堆燃爆,并有可能引起附近的草堆连环燃爆。游戏的目标是玩家用一些奶牛燃爆所有的草堆。
有N个草堆在数轴的不同位置,坐标为x1,x2,….,xn。如果玩家把奶牛发射到坐标是x,能量是R,就会引爆半径R以内的的草堆,即坐标范围[x-R, x+r]的草堆都会燃爆。
现在有K头奶牛,每头奶牛的能量都是R,请计算如果要引爆所有的草堆,最小的R是多少?


输入格式

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


输出格式

输出最小可能的R。


输入样例
7 2
20
25
18
8
10
3
1
输出样例

5

【题意分析】

        数据是50000,所以,O(n^2)的算法(直接枚举R)是不可取的。所以,我们可以二分R,并记要引爆所有草堆最少需要奶牛的个数为sum,假如奶牛的个数大于等于题目中所描述的K,然后就向右边缩小范围(即l=mid+1),因为这时侯R的值太小了;否则就向左缩小范围(r=mid)。最后输出l,就可以了。

        现在问题来了:怎样计算最少的奶牛个数?我们可以用last记为从0到last的草堆已被炸掉(那么前面就要先把草堆进行排序),那么只要用贪心,在x[ last+1 ]+R的地方把奶牛扔过去,再统计能被引爆的个数并加到last上。直到草堆全部炸完为止。这样时间复杂度是O(n)。
 

#include<cstdio>
#include<algorithm>
using namespace std;
int minx=0x0fffffff,maxx=-0x0fffffff;
int a[50011];
int n,k,l,r,mid;
int t,sum,ans=0x0fffffff,p;
int last;

int main()
{
 
 scanf("%d%d",&n,&k);
 for(int i=0;i<n;i++)
 {
  scanf("%d",&a[i]);
  minx=min(minx,a[i]);
  maxx=max(maxx,a[i]);
 }
 sort(a,a+n);   //把草堆的位置排序
 
 l=0; r=maxx-minx;
 
 while(l<r)//二分R
 {

  mid=(l+r)/2;
  
  last=0;
  sum=0;
  t=0;
  
  while(last<n)//统计最少需要奶牛的个数
  {
   t=a[last+1]+mid;
   p=last+1;
   
   while(p<n && a[p]-a[last]<=(mid<<1)) p++;
   last=p;
   sum++;
  }
  
 
  if(sum<=k) r=mid;
  else l=mid+1;
  
  
 }
 printf("%d",l);//输出最少的R
 return 0;
}


0 0
原创粉丝点击