• POJ1054 The Troublesome Frog


    题目来源:http://poj.org/problem?id=1054

    题目大意:

      有一种青蛙在晚上经过一片稻田,在庄稼上跳跃,会把庄稼压弯。这让农民很苦恼。我们希望通过分析青蛙跳跃的路径,找出对稻田造成最大损害的青蛙。青蛙跳跃时总是沿着直线并且步长均匀,但不同青蛙可能步长或方向不一样。如下图所示:

      稻田庄稼是均匀地种在矩形网格交点处的,如下左图所示。青蛙总是会完全穿过这片稻田,也就是说从稻田外跳入并最终跳出稻田。如下右图所示。

      有许多青蛙会穿过这片稻田,从庄稼上跳跃。我们可以知道那些庄稼被青蛙“踩”过,有的庄稼可能被多只青蛙踩过。但是我们并不知道青蛙的路径是怎样的。也就是说对于下左图的青蛙路径,我们只能知道下右图中的青蛙脚印点坐标。

      从Figure4,我们分析所有可能的青蛙路径,我们只关心脚印数大于3的路径,目标是找出所有可能的青蛙路径中脚印数最多的路径。Figure4对应的答案应该是7.

    输入:第一行含两个整数R和C,表示稻田的行和列。1 <= R,C <= 5000.第二行为一个整数N,表示被压扁的庄稼数(即青蛙的脚印数),3 <= N <= 5000。接下来N行每行为一对整数,表示脚印坐标:行号r(1 <= r <= R)和列号c(1 <= c <= C),每个坐标只出现一次。

    输出:一个整数表示穿过稻田留下脚印最多的青蛙的脚印数,如果找不到符合要求的青蛙路径输出0。


    Sample Input

    6 7
    14
    2 1
    6 6
    4 2
    2 5
    2 6
    2 7
    3 4
    6 1
    6 2
    2 3
    6 3
    6 4
    6 5
    6 7
    

    Sample Output

    7

    首先,暴力解决本题的思路是,遍历所有的脚印对,检查这两个脚印确定的直线可否穿过这对脚印形成青蛙路径,若可组成青蛙路径,记下路径的脚印数,然后找出路径上脚印数的最大值。这样做的问题是:一条路径上可能有很多点,那么每条路径都可能被计算多次,导致时间上的浪费。

    可以用下面的方法来避免这个问题:我们假定青蛙在大方向上都是从稻田的一侧跳向另一侧,分别称为起点侧和终点侧。对于任意一条脚印路径,我们只在选取的脚印对(脚印对视为有序对,(i,j)和(j,i)为不同的脚印对)是路径上最靠近起点侧的两个脚印且i比j更靠近起点侧(或距离相等)时才检查一次这条路径(可以理解为 i 是青蛙跳进稻田第一步的脚印,j 是第二步的脚印),从而保证每条路径恰好被计算一次。

    具体做法为:

    首先,将所有脚印点进行排序。点的坐标(x, y), 排序策略为,首先按x由小到大排序,对于x相等的点再按列好从小到大排。

    然后,对于排好序之后的脚印点,按顺序遍历脚印对时,假定第i个脚印点和第j个脚印点的坐标为(xi, yi), (xj, yj). 那么当 j > i 时,一定有xj >= xi。由前述的避免重复计算路径的策略,我们只计算所有的j>i的脚印对,即j一定是在经过i之后才到达的。

    接下来,如何保证 i 和 j 恰好是最靠近起点侧的脚印(即青蛙跳进稻田后的第一步和第二步留下的脚印)?方法是:让青蛙“往回跳一步”,假定往回跳一步还在稻田内,那么有两种可能,一,回退一步的坐标是脚印点,那么这条直线可能形成路径,但不应该在遍历脚印点 i 和 j 时被计算,二,回退一步的坐标不是脚印点,那么这条直线不能穿过 i 和 j 形成青蛙路径,因为青蛙的步长是定值,无法直接从田外直接跳到 i。所以,只要青蛙回退一步的坐标仍然在田内,则这对脚印不可能符合要求,可以不用计算对应的路径。

    再然后,并不是所有符合上面条件的 i 和 j 都会确定出一条可行的青蛙路径。(比如上面Figure4中的(2,2)和(3,4),所在的直线就不能组成可行路径)。判断方法就是假设路径可行,由已知的两个点已经知道青蛙的步长和方向,模拟青蛙向前跳,如果青蛙恰好沿脚印点跳出稻田,说明路径可行,否则不可行。

    至此似乎已经可以比较好的解决这个这个问题了,不过还有一些优化的策略:

    1.由于青蛙沿直线跳跃且一定会穿越整片稻田,那么脚印数一定有一个上界--稻田的长和宽中的较大值。若已经有某条路径达到了上界,则不需要再搜索和计算。

    2.当确定一对要检查的脚印对 i 和 j 后,我们是假定这条路径可行,那么我们已经知道了假定的路径中青蛙的步长、方向和起点,所以我们可以预测出该条路径的脚印点数,如果脚印数小于已找到的最大值,则没有必要再检查这对点对应的路径了。

    3.我们在排序时不一定要固定按行排或按列排。按长度方向较小的方向为主序来排序可以使排序发挥更大的作用。

    按照上述的各种策略课将题目由TLE加快到100ms内完成。 

    最后要注意需要输出0的情况。

      1 ///////////////////////////////////////////////////////////
      2 //        POJ1054 The Troublesome Frog
      3 //        Memory: 172K        Time: 63MS
      4 //        Language: C++        Result: Accepted
      5 //////////////////////////////////////////////////////////
      6 
      7 #include <cstdio>
      8 #include <cstdlib>
      9 
     10 using namespace std;
     11 
     12 struct Plant {
     13     int x, y;
     14 };
     15 
     16 Plant foot_print[5001];
     17 int r, c, n;
     18 int max_steps = 2;
     19 
     20 int cmp_x(const void * a, const void * b) {
     21     Plant * pa = (Plant *) a;
     22     Plant * pb = (Plant *) b;
     23     if (pa->x == pb->x) {
     24         return pa->y - pb->y;
     25     } else {
     26         return pa->x - pb->x;
     27     }
     28 }
     29 
     30 int cmp_y(const void * a, const void * b) {
     31     Plant * pa = (Plant *) a;
     32     Plant * pb = (Plant *) b;
     33     if (pa->y == pb->y) {
     34         return pa->x - pb->x;
     35     } else {
     36         return pa->y - pb->y;
     37     }
     38 }
     39 
     40 int check_x(int j, int dx, int dy) {
     41     int ans = 2;
     42     Plant plant;
     43     plant.x = foot_print[j].x + dx;
     44     plant.y = foot_print[j].y + dy;
     45     while (plant.x <= r && plant.y <= c && plant.y >= 1) {
     46         if (bsearch(&plant, foot_print, n, sizeof(Plant), cmp_x)) {
     47             plant.x += dx;
     48             plant.y += dy;
     49             ++ans;
     50         } else {
     51             return 0;
     52         }
     53     }
     54     return ans;
     55 }
     56 
     57 int check_y(int j, int dx, int dy) {
     58     int ans = 2;
     59     Plant plant;
     60     plant.x = foot_print[j].x + dx;
     61     plant.y = foot_print[j].y + dy;
     62     while (plant.x >= 1 && plant.x <= r && plant.y <= c) {
     63         if (bsearch(&plant, foot_print, n, sizeof(Plant), cmp_y)) {
     64             plant.x += dx;
     65             plant.y += dy;
     66             ++ans;
     67         } else {
     68             return 0;
     69         }
     70     }
     71     return ans;
     72 }
     73 
     74 
     75 int main(void) {
     76     scanf("%d%d%d", &r, &c, &n);
     77     for (int i = 0; i < n; ++i) {
     78         scanf("%d%d", &foot_print[i].x, &foot_print[i].y);
     79     }
     80     if (r > c) {
     81         if (r > 2) {
     82             qsort(foot_print, n, sizeof(Plant), cmp_x);
     83             for (int i = 0; i < n - 2; ++i) {
     84                 for (int j = i + 1; j < n - 1; ++j) {
     85                     int dx = foot_print[j].x - foot_print[i].x;
     86                     int dy = foot_print[j].y - foot_print[i].y;
     87                     int px = foot_print[i].x - dx;
     88                     int py = foot_print[i].y - dy;
     89                     if (px >= 1 && py >= 1 && py <= c) {
     90                         continue;
     91                     }
     92                     px = foot_print[i].x + max_steps * dx;
     93                     if (px > r) {
     94                         break;
     95                     }
     96                     py = foot_print[i].y + max_steps * dy;
     97                     if (py < 1 || py > c) {
     98                         continue;
     99                     }
    100                     int ans = check_x(j, dx, dy);
    101                     if (ans > max_steps) {
    102                         max_steps = ans;
    103                     }
    104                     if (max_steps == r) {
    105                         printf("%d
    ", max_steps);
    106                         return 0;
    107                     }
    108                 }
    109             }
    110         }
    111     } else if (c > 2) {
    112         qsort(foot_print, n, sizeof(Plant), cmp_y);
    113         for (int i = 0; i < n - 2; ++i) {
    114             for (int j = i + 1; j < n - 1; ++j) {
    115                 int dx = foot_print[j].x - foot_print[i].x;
    116                 int dy = foot_print[j].y - foot_print[i].y;
    117                 int px = foot_print[i].x - dx;
    118                 int py = foot_print[i].y - dy;
    119                 if (px >= 1 && px <= r && py >= 1) {
    120                     continue;
    121                 }
    122                 py = foot_print[i].y + max_steps * dy;
    123                 if (py > c) {
    124                     break;
    125                 }
    126                 px = foot_print[i].x + max_steps * dx;
    127                 if (px < 1 || px > r) {
    128                     continue;
    129                 }
    130                 int ans = check_y(j, dx, dy);
    131                 if (ans > max_steps) {
    132                     max_steps = ans;
    133                 }
    134                 if (max_steps == c) {
    135                     printf("%d
    ", max_steps);
    136                     return 0;
    137                 }
    138             }
    139         }
    140     }
    141     if (max_steps <= 2) {
    142         max_steps = 0;    
    143     }
    144     printf("%d
    ", max_steps);
    145     return 0;
    146 }
    View Code
  • 相关阅读:
    EasyARM-iMX283A的Linux 开发环境构建
    linux指令tar笔记
    使用cuteFTP与虚拟机交互文件---安装ftp服务
    SecureCRT显示乱码的解决办法
    【转】简明 Vim 练级攻略
    图像识别___YUV学习手记
    一个简易的软件定时器
    OV7670配置和调试小结
    linux驱动开发( 五) 字符设备驱动框架的填充file_operations结构体中的操作函数(read write llseek unlocked_ioctl)
    hash-1.hash表和hash算法
  • 原文地址:https://www.cnblogs.com/dengeven/p/3267072.html
Copyright © 2020-2023  润新知