Description

In Korea, the naughtiness of the cheonggaeguri, a small frog, is legendary. This is a well-deserved reputation, because the frogs jump through your rice paddy at night, flattening rice plants. In the morning, after noting which plants have been flattened, you want to identify the path of the frog which did the most damage. A frog always jumps through the paddy in a straight line, with every hop the same length: 
 
Your rice paddy has plants arranged on the intersection points of a grid as shown in Figure-1, and the troublesome frogs hop completely through your paddy, starting outside the paddy on one side and ending outside the paddy on the other side as shown in Figure-2: 
 
Many frogs can jump through the paddy, hopping from rice plant to rice plant. Every hop lands on a plant and flattens it, as in Figure-3. Note that some plants may be landed on by more than one frog during the night. Of course, you can not see the lines showing the paths of the frogs or any of their hops outside of your paddy ?for the situation in Figure-3, what you can see is shown in Figure-4: 
 
From Figure-4, you can reconstruct all the possible paths which the frogs may have followed across your paddy. You are only interested in frogs which have landed on at least 3 of your rice plants in their voyage through the paddy. Such a path is said to be a frog path. In this case, that means that the three paths shown in Figure-3 are frog paths (there are also other possible frog paths). The vertical path down column 1 might have been a frog path with hop length 4 except there are only 2 plants flattened so we are not interested; and the diagonal path including the plants on row 2 col. 3, row 3 col. 4, and row 6 col. 7 has three flat plants but there is no regular hop length which could have spaced the hops in this way while still landing on at least 3 plants, and hence it is not a frog path. Note also that along the line a frog path follows there may be additional flattened plants which do not need to be landed on by that path (see the plant at (2, 6) on the horizontal path across row 2 in Figure-4), and in fact some flattened plants may not be explained by any frog path at all.

Your task is to write a program to determine the maximum number of landings in any single frog path (where the maximum is taken over all possible frog paths). In Figure-4 the answer is 7, obtained from the frog path across row 6.

Input

Your program is to read from standard input. The first line contains two integers R and C, respectively the number of rows and columns in your rice paddy, 1 <= R,C <= 5000. The second line contains the single integer N, the number of flattened rice plants, 3 <= N <= 5000. Each of the remaining N lines contains two integers, the row number (1 <= row number <= R) and the column number (1 <= column number <= C) of a flattened rice plant, separated by one blank. Each flattened plant is only listed once.

Output

Your program is to write to standard output. The output contains one line with a single integer, the number of plants flattened along a frog path which did the most damage if there exists at least one frog path, otherwise, 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

Source

 
 

解题思路
这个问题看起来很复杂,其实目的很简单:帮助农民找到为害最大的青蛙。也就是要找到
一条穿越稻田的青蛙路径,这个路径上被踩踏的水稻不少于其他任何青蛙路径上被踩踏的水
稻数。当然,整个稻田中也可能根本就不存在青蛙路径。问题的关键是:找到穿越稻田的全
部青蛙路径。任何一条穿越稻田的青蛙路径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)上的水稻必被
青蛙踩踏
根据上述规则,只要知道一条青蛙路径上的前两棵被踩踏的水稻,就可以找到该路径上其
他的水稻。为了找到全部的青蛙路径,只要从被踩踏的水稻中,任取两棵水稻(X1,Y1)、(X2,
Y2),判断(X1,Y1)、(X2,Y2)是否能够作为一条青蛙路径上最先被踩踏的两颗水稻。
解决方案
这个问题的描述中,最基本的元素是被踩踏的水稻。在程序中要选择一个合适的数据结构,
来表达这个基本元素。这个数据结构是否合适的标准是:在程序中要表达这个元素时,能否
用一个单词或者短语,即用一个变量来表示。
struct PLANT {//描述一棵被踩踏的水稻
int x; //水稻的行号
int y; //水稻的列号
}
这个问题的主要计算是:从被踩踏的水稻中选择两棵(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是稻田中被踩踏水稻的总量。

参考程序

 //By LYLtim
//2015.2.3 #include <iostream>
#include <algorithm>
using namespace std; class Plant
{
public:
int x, y;
bool operator< (const Plant& p2) const { // binary_search 3rd argument const T& val
if (x == p2.x)
return y < p2.y;
return x < p2.x;
}
}; int r, c, n;
Plant plants[]; int searchPath(const Plant secPlant, const int dx, const int dy){
Plant tmpPlant;
int steps = ;
tmpPlant.x = secPlant.x + dx;
tmpPlant.y = secPlant.y + dy;
while( (tmpPlant.x <= r) && (tmpPlant.y >= ) && (tmpPlant.y <= c) ) {
if (!binary_search(plants, plants + n, tmpPlant)) {
//每一步都必须踩倒水稻才算合理, 否则这就不是一条行走路径
steps = ;
break;
}
steps++; //print
// cout << tmpPlant.x << "," << tmpPlant.y << endl; tmpPlant.x += dx;
tmpPlant.y += dy;
}
return steps;
} int main()
{
int dx, dy, px, py, max = , steps;
cin >> r >> c;
cin >> n;
for (int i = ; i < n; i++)
cin >> plants[i].x >> plants[i].y;
sort(plants, plants + n); //print plants
// for (int i = 0; i < n; i++)
// cout << plants[i].x << " " <<plants[i].y << endl; for (int i = ; i < n-; i++)
for (int j = i+; j < n-; 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>=) && (py>=) && (py<=c))
continue;
if (plants[i].x + (max-)*dx > r)
break;
py = plants[i].y + (max-)*dy;
if ( (py<) || (py>c) )
continue; //print
// cout << "p1:" << plants[i].x << "," << plants[i].y << " p2:"<<plants[j].x << "," << plants[j].y << " dx,dy: " << dx << "," << dy << endl; steps = searchPath(plants[j], dx, dy); //print steps
// cout << "steps:" <<steps << endl << endl; if (steps > max)
max = steps;
}
if (max == )
max = ;
cout << max;
return ;
}
 
PS:5年没碰算法题了。。好沧桑。。最近刚学C++才练下,代码不好请见谅。。

IOI2002 POJ1054 The Troublesome Frog 讨厌的青蛙 (离散化+剪枝)的更多相关文章

  1. POJ1054 The Troublesome Frog

    题目来源:http://poj.org/problem?id=1054 题目大意: 有一种青蛙在晚上经过一片稻田,在庄稼上跳跃,会把庄稼压弯.这让农民很苦恼.我们希望通过分析青蛙跳跃的路径,找出对稻田 ...

  2. poj1054 The Troublesome Frog 瞎搞。

    连接:http://poj.org/problem?id=1054 题意:就是一个格子里一条线上最长有几个青蛙(青蛙间隔相同)~.但是其实青蛙的起点重点必须是在外面. 直接写一个搜就是. #inclu ...

  3. POJ 1054 The Troublesome Frog

    The Troublesome Frog Time Limit: 5000MS Memory Limit: 100000K Total Submissions: 9581 Accepted: 2883 ...

  4. Poj 1054 The Troublesome Frog / OpenJudge 2812 恼人的青蛙

    1.链接地址: http://poj.org/problem?id=1054 http://bailian.openjudge.cn/practice/2812 2.题目: 总时间限制: 10000m ...

  5. POJ 1054 The Troublesome Frog(枚举+剪枝)

    题目链接 题意 :给你r*c的一块稻田,每个点都种有水稻,青蛙们晚上会从水稻地里穿过并踩倒,确保青蛙的每次跳跃的长度相同,且路线是直线,给出n个青蛙的脚印点问存在大于等于3的最大青蛙走的连续的脚印个数 ...

  6. (中等) POJ 1054 The Troublesome Frog,记忆化搜索。

    Description In Korea, the naughtiness of the cheonggaeguri, a small frog, is legendary. This is a we ...

  7. The Troublesome Frog

    In Korea, the naughtiness of the cheonggaeguri, a small frog, is legendary. This is a well-deserved ...

  8. poj 1054 The Troublesome Frog (暴力搜索 + 剪枝优化)

    题目链接 看到分类里是dp,结果想了半天,也没想出来,搜了一下题解,全是暴力! 不过剪枝很重要,下面我的代码 266ms. 题意: 在一个矩阵方格里面,青蛙在里面跳,但是青蛙每一步都是等长的跳, 从一 ...

  9. 【POJ】1054 The Troublesome Frog

    题目是非常经典的搜索+剪枝.题意简言之就是,青蛙需要沿着直线踩着踏点通过田地,并且踏点需要至少为3.问哪条路径青蛙踩坏的作物最多.很好的一个条件是青蛙每次移动都是等间距的.题目需要注意将其排序. #i ...

随机推荐

  1. 06_MySQL DQL_分组查询

    # 分组查询/*语法: select 分组函数,列(group by中出现的字段) from 表 [where 筛选条件] group by 分组的列表(单个字段,多个字段,函数,表达式) [havi ...

  2. NPM Scripts -- onchange parallelshell

    Watch for changes to the styles.scss file and automatically compile it to the css file. Run multiple ...

  3. Yii框架(一)

    这里接触了 MVC 设计模式中的控制器和视图部分. 创建了一个操作作为控制器的一部分去处理特定请求. 然后又创建了一个视图去构造响应内容. 在这个小例子中,没有模型调用,唯一涉及到数据的地方是 mes ...

  4. TensorFlow备忘录——conv2d函数

    卷积函数 TensorFlow学习备忘录 tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_forma ...

  5. iQuery移动端手势事件插件-jGestures

    jGestures下载 jGestures事件简介 orientationchange 代表设备顺时针或者逆时针旋转.此事件可以被设备触发,可能使用的是重力传感器. pinch 缩放手势(两个手指在屏 ...

  6. AOP(面向切面)的粗俗理解

    百度百科的解释:AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. 一个比较绕的概念,简单来说就是把不影响业 ...

  7. 【hive】子查询

    hive中是不支持子查询的 但是并不意味这不支持in 或者 not in in 或者not in 后边是定值的话是支持的 但是接定制是可以的 例如 select id from table not i ...

  8. laravel中Crypt加密方法

    使用Crypt::encrypt对数据进行加密,要引入 use Illuminate\Support\Facades\Crypt;;  对使用Crypt::encrypt加密的数据进行解密的方法时:C ...

  9. 004——数组(四)array_search() array_change_key_case() array_chunk() array_combine() array_diff() array_diff_key() array_diff_assoc

    <?php /** * in_array() 判断一个内容是否在数组中: */ /*$arr=array(1,2,3,4,5); if (in_array('1',$arr,TRUE)){ // ...

  10. Spark安装和简单示例

    spark的安装 先到官网下载安装包 注意第二项要选择和自己hadoop版本相匹配的spark版本,然后在第4项点击下载.若无图形界面,可用windows系统下载完成后传送到centos中. 本例中安 ...