第十一届山东省大学生程序设计竞赛(热身赛)C-Mika with Cherry Cake(贪心)

C-Mika with Cherry Cake

  • 题意:
  • 思路
  • 代码

链接

题意:

有一个二维平面,一个人a一开始在(0,0)处,平面上有n个商人,你可以操纵a移动,从(x1,y1)移动到(x2,y2)处需要花费|x1-x2|+|y2-y1|秒,如果a移动可以跟商人移动到一点的话,就获得了一个樱桃,然后如果获得了这个樱桃的话,a必须再移动回原点,注意a移动的过程中,商人也会单方向(上、下、左、右)移动,问你a最多能获得多少个樱桃?

思路

可以发现 :
1.假设经过时间t时a可以追上商人,设初始时商人的坐标为(x,y) 经过试试可以知道 比如d=1或者3(向上或者向右走的商人),列个时间的等式:x+y+t=t这种直接约掉了t,所以是追不上的。
所以只有d=2或者4的商人才可能被追上 而且以 d=2向下走为例 x+|y-t|=t 只有当绝对值为正这个方程才有解,所以只要能追上商人,时间t必为 (x+y)/2 。

2.而且d=2或者4的商人是有可能走不到的 :
以d=2为例,商人坐标为(x,y),a(一开始在原点处)需要先走x秒到(x,0) 然后再纵坐标走y,如果商人(x,y) 其y

3.然后为啥只用找一遍所有的商人而不是一直找直至找不到能走的商人呢?
问了wlx大佬才懂了
答:如果a走到一个商人(x,y)了,然后a回去,商人在这个过程中纵坐标y要减去总时间(x+y),由于x、y均大于0,所以y就小于0了。
类比于上面讲的那个例子,商人一开始纵坐标就小于0了,a走到(x,0)时商人纵坐标也小于0,a和商人纵坐标以相同的速度减小,所以:追到过的商人是不可能再追上的。
综上只需要遍历一次所有商人就好

4.然后本题还需要按x+y升序排序,因为追个商人来回花费的时间t,你需要花费一个综合起来少的时间去追下一个商人,因为这样
才能追到尽可能多的商人,不然不排序的话:比如说第一个商人非常远,为了追上这个牺牲了很多很小的,就不是最优的了

代码

#include 
#include 
#include 
#include
#include
using namespace std;
typedef long long ll;
double eps=1e-8;
struct w{
     
	double x;
	double y;
	int d;
	bool operator<(const w& z)const{
     
	return x+y<z.x+z.y;}
}a[6000];
int cnt,sum;
bool can=false;
int main()
{
     
   int n;
   cin>>n;
   for(int i=0;i<n;i++) {
     
   	int x,y,d;
   	cin>>x>>y>>d;
   	if(d==2||d==4){
     
   		  a[cnt].x=x;
   		  a[cnt].y=y;
   		  a[cnt].d=d;
   		  
   		  cnt++;
	   }
   }
   int ti=0;
   sort(a,a+cnt);
   for(int i=0;i<cnt;i++){
     
   	   if(a[i].d==2){
     
   	   	     a[i].y-=ti;
		  }
	   else{
     
	   	a[i].x-=ti;
	   }
	   if(a[i].d==2){
     
	   	   if(a[i].y<a[i].x) continue;
	   	   sum++;
	   	   ti+=a[i].x+a[i].y;
	   }
	  else{
     
	  	 if(a[i].x<a[i].y) continue;
	   	   sum++;
	   	   ti+=a[i].x+a[i].y;
	  }
   }
   cout<<sum;
     
}

你可能感兴趣的:(acm竞赛)