枚举 讨厌的青蛙

这个问题的主要计算是:从被踩踏的水稻中选择两棵(X1,Y1)、(X2,Y2)。判断它们是否 能够作为一条青蛙路径上最先被踩踏的两颗水稻。(X1,Y1)、(X2,Y2)唯一确定了蛙跳的方 向和步长,从(X2,Y2)开始,沿着这个方向和步长在稻田内走。每走一步,判断所到达位置 上(X,Y)的水稻是否被踩踏,直到走出稻田为止。如果在某一步上,(X,Y)没有被踩踏, 则表明(X1,Y1)、(X2,Y2)是一条青蛙路径上最先被踩踏的两颗水稻的假设不成立。这个判 断的算法在问题求解过程中要反复使用,它的效率成为决定整个计算效率的关键。
 用一个PLANT 型的数组plants[5001]表示全部被踩踏的水稻
 将plants 中的元素按照行/列序号的升序(或者降序)排列
 采用二分法查找plants 中是否有值为(X,Y)的元素:将(X,Y)与plants 中间的元素比较,

(1)相等,表明找到了元素;(2)比plants 中间元素的小,继续在plants 的前半部寻找;(3)比plants 中间元素的大,继续在plants 的后半部寻找。采用上述方法判断每走一步所到达位置上(X,Y)的水稻是否被踩踏,最多只要比较Log2N,其中N 是稻田中被踩踏水稻的总量。


代码:

#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int r,c,n;
struct PLANT{
    int x, y;
};
PLANT plants[5001];
PLANT plant;
int searchPath(PLANT secPlant, int dX, int dY);


int main() {
    int i, j, dX, dY, pX, pY, steps, max=2;
    scanf("%d %d", &r, &c);
    //行数和列数,x方向是上下,y方向是左右
    scanf("%d", &n);
    for(i=0; i<n; i++) {
        scanf("%d %d", &plants[i].x, &plants[i].y);
    }
    //将水稻按x坐标从小到大排序,x坐标相同按y从小到大排序
    sort(plants, plants+n);
    for(i=0; i<n-2; i++) { //plants[i]是第一个点
        for(j=i+1; j<n-1; j++) { //plants[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;
                //第一个点的前一点在稻田里
                //说明本次选的第二点导致的x方向步长不合理(太小)
                //取下一个点作为第二点
            }
            if (plants[i].x+(max-1)*dX>r) {
                break;
                //x方向过早越界了,说明本次选的第二点不成立
                //如果换下一个点作为第二点,x方向步长只会更大,更不成立,所以应该
                //认为本次选的第一点必然是不成立的,那么取下一个点作为第一点再试
            }
            pY = plants[i].y+(max-1)*dY;
            if (pY>c || pY<1) {  //感觉此步没必要判断小于号啊,NodYoung注
                continue;//y方向过早越界了,应换一个点作为第二点再试
            }
            steps = searchPath(plants[j], dX, dY);
            if (steps>max) {
                max = steps;
            }
        }       
    }
    if (max == 2) {
        max = 0;
    }
    printf("%d\n", max);
}
/*
运算符重载,用于sort
*/
bool operator < (const PLANT &p1, const PLANT &p2) {
    if (p1.x == p2.x) {
        return p1.y<p2.y;
    }
    return p1.x < p2.x;
}


//判断从secPlant点开始,步长为dx,dy, 那么最多能走几步
int searchPath(PLANT secPlant, int dX, int dY) {
    PLANT plant;
    int steps;
    plant.x = secPlant.x + dX;
    plant.y = secPlant.y + dY;
    steps = 2;
    while(plant.x<=r && plant.x>=1 && plant.y<=c && plant.y>=1) {
        if (!binary_search(plants, plants+n, plant)) {
            //每一步都必须踩倒水稻才算合理,否则这就不是一条行走路径
            steps = 0;
            break;
        }
        plant.x += dX;
        plant.y += dY;
        steps++;
    }
    return steps;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值