POJ 1054 讨厌的青蛙

考察要点:优化判断条件,枚举,

技巧:qsort 和 bsearch 库函数的使用

解题思路:

(1)  任何一条穿越稻田的青蛙路径L,至少包括3 棵被踩踏的水稻。假设其中前两
棵被踩踏的水稻分别是(X1,Y1)、(X2,Y2),那么:
* 令 dx=X2-X1、dy=Y2-Y1;X0=X1-dx、Y0=Y1- dy;X3=X2 + dx、Y3=Y2 + dy
* (X0,Y0)位于稻田之外,青蛙从该位置经一跳后进入稻田、踩踏位置(X1,Y1)上的水稻
*(X3,Y3)位于稻田之内,该位置是L 上第3 棵被青蛙踩踏的水稻
* Xi=X0 + idx、Yi=Y1 + idy(i3),如果(Xi,Yi)位于稻田之内,则(Xi,Yi)上的水稻必被
青蛙踩踏

(2)  从被踩踏的水稻中选择两棵(X1,Y1)、(X2,Y2)。判断它们是否
能够作为一条青蛙路径上最先被踩踏的两颗水稻。(X1,Y1)、(X2,Y2)唯一确定了蛙跳的方
向和步长,从(X2,Y2)开始,沿着这个方向和步长在稻田内走。每走一步,判断所到达位置
上(X,Y)的水稻是否被踩踏,直到走出稻田为止。

(3)  用一个 PLANT 型的数组plants[5001]表示全部被踩踏的水稻
*将 plants 中的元素按照行/列序号的升序(或者降序)排列
*采用二分法查找 plants 中是否有值为(X,Y)的元素:将(X,Y)与plants 中间的元素比较,
(1)相等,表明找到了元素;(2)比plants 中间元素的小,继续在plants 的前半部寻找;(3)
比plants 中间元素的大,继续在plants 的后半部寻找。


/**   POJ 1054        **/
#include <stdio.h>
#include <stdlib.h>

int r ,c,n;//行、列、和被踩水稻数

struct PLANT
{
    int x;
    int y;
};

PLANT plants[5001];
PLANT plant;

int cmp(const void *elem1,const void *elem2);//定义比较函数 对水稻行列进行排序
int Binsearch(PLANT secPant,int dx,int dy); //在plants中查找是否有(X,Y)

int main()
{
    freopen("in.txt","r",stdin);
    int i,j,dx,dy,px,py,steps,max=2;
    scanf("%d%d",&r,&c);
    scanf("%d",&n);
    for(i=0;i<n;i++)
    scanf("%d%d",&plants[i].x,&plants[i].y);
    qsort(plants,n,sizeof(PLANT),cmp); //排序
    for(i=0;i<n-2;i++)
      for(j=i+1;j<n-1;j++)
      {
          dx = plants[j].x - plants[i].x;  //计算被踩的水稻水平距离
          dy = plants[j].y - plants[i].y;  //计算被踩的水稻水平距离
          px = plants[i].x - dx;           //计算下一棵被踩水稻的横坐标
          py = plants[i].y - dy;           //计算下一棵被踩水稻的纵坐标
          if(px<=r&&px>=1&&py<=c&&py>=1)   //如果没有越界
          continue;
          if((plants[i].x + max *dx)>r)    //越界则 排除此情况
          break;
          py = plants[i].y +max *dy;       
          if(py>c||py<1) 
          continue;
          steps = Binsearch(plants[j],dx,dy); //在plants数组中查找是否存在计算出的坐标
          if(steps>max) max = steps;       //更新最大被踩水稻棵数
      }
      if(max == 2) max = 0;  //至少3棵
      printf("%d\n",max);
      return 0;
}

int cmp(const void *elem1,const void *elem2)
{
    PLANT *p1,*p2;
    p1 = (PLANT *)elem1;
    p2 = (PLANT *)elem2;
    if(p1->x == p2->x) return p1->y -p2->y; //按行号或列号升序排列
    return p1->x - p2->x;
}

int Binsearch(PLANT secPant,int dx,int dy)
{
    PLANT plant;  
    int steps;
    plant.x = secPant.x + dx; 
    plant.y = secPant.y + dy;

    steps = 2; //初始值 为2;
    while(plant.x<=r&&plant.x>=1&&plant.y<=c&&plant.y>=1)
    {
        if(!bsearch(&plant,plants,n,sizeof(PLANT),cmp)) //如果查找不到(X,Y)
        {
            steps = 0;  
            break ;
        }
        plant.x += dx;   //计算出下一颗的坐标
        plant.y += dy;
        steps++;        //查找成功 ,棵数增加
    }
    return (steps);  
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值