挑战程序设计竞赛 # POJ 1852 Ants

版权声明:转载请注明原文地址即可,要是本文对您有些许帮助的话,请您在下方点个赞,谢谢啦ヾ(o◕∀◕)ノヾ https://blog.csdn.net/qq_33583069/article/details/86713757

Description

n个蚂蚁,速度1cm/s,在水平杆上运动。
已知:n个蚂蚁在杆上的分布
未知:每个蚂蚁的朝向
求:所有蚂蚁都离开杆的最小和最大时间。


Key 贪心入门

划重点:所有蚂蚁。
一个很有意思的描述就是,两只蚂蚁不能交错,相遇的话就各自反向,不计碰撞时间
这句话就是本题的破局点。

第一次接触算法的同学可能会有点懵。所以我写细一点。再简化问题,假设初始条件有蚂蚁的朝向,并且是求最先掉下去的蚂蚁的时间,那么这个题是不是很好做?最小时间好求吗?显然最先掉下去的一定在杆的最左侧或者最右侧,为什么呢?请想一想。由于碰撞的奇特性质,两只蚂蚁之间的相对次序是不可能发生改变的,只能改变方向,所以最先离开的一定是两侧的蚂蚁,至多可能会碰撞一次然后落下去或者直接就掉下去了(没有碰撞就很好处理啦。故我就不说啦)。然后如果要计算时间的话,可以先写一个collision函数(分方向哟~)假设最左侧,对它算它和次左的蚂蚁的碰撞时间,如果同向的话就直接计算就好啦,(x2-x1)/2+x1。如果不是的话emmm对次左的蚂蚁再用一次collision函数(递归出来了!嘻嘻,没有学递归的读者emm请忽略这里)…然后读者应该就明白了。如果未知朝向,那么掉下的时间就无法确定,那么可以假设朝向然后算最小、最大时间,显然最小是两侧蚂蚁离两端的距离最小值,最大是两端的蚂蚁都要发生碰撞再掉落下去的时间的min值。
上面分析的是第一只蚂蚁的掉落时间,但是从这个分析过程中我们看到了本题碰撞的奇妙性质,这让我们不由得想一想,这个这么好的性质,还有什么用呢?上面是对个体,那对群体这个性质有什么效果呢?
请仔细想想~
假设读者思考过了,嗯~你会发现原来由于次序不会发生改变,那么,群体离开的时间=最后一个个体的离开时间,由于碰撞这个奇妙的性质,你会发现,原来,如果要使时间最小,最后一个下落的一定是位于中间(分奇偶哟hh)的蚂蚁(换个描述的话就是离杆的中点最近的蚂蚁),群体掉落时间的最小值就是它到某端的距离的最小值(速度是1cm/s)最大值也就显然啦(最后一个离开的在两侧),是不是很有趣鸭hh
这就是奇特的贪心算法。

啦啦啦啦~代码实现也就很好写啦
然后我们再考虑一下本题不用贪心的做法,比如说,对所有的蚂蚁的朝向都枚举一次,然后再模拟~哇,指数级时间诶 ,是不是感觉到了贪心的优越性!hhh

参考code:
注意minans这里有坑~

#include <iostream>
using namespace std;
#define N 1000000
int len,n,pos[N];
int main(){
 ios::sync_with_stdio(0);
 int T;  cin>>T; 
 while(T--){
  cin>>len>>n;
  int minans = -1,maxans = -1;
  for(int i=1;i<=n;i++)cin>>pos[i]; 
  for(int i=1;i<=n;i++){
   minans = max(minans,min(pos[i],len-pos[i]));
   maxans = max(maxans,max(pos[i],len-pos[i]));
  }
  cout<<minans<<" "<<maxans<<endl;
 }
 return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33583069/article/details/86713757