总时间限制: 2000ms 单个测试点时间限制: 500ms 内存限制: 65536kB

描述

在韩国,有一种小的青蛙。每到晚上,这种青蛙会跳越稻田,从而踩踏稻子。农民在早上看到被踩踏的稻子,希望找到造成最大损害的那只青蛙经过的路径。每只青蛙总是沿着一条直线跳越稻田,而且每次跳跃的距离都相同。

POJ 2812 恼人的青蛙 - 图1

稻子组成一个栅格,每棵稻子位于一个格点上。而青蛙总是从稻田的一侧跳进稻田,然后沿着某条直线穿越稻田,从另一侧跳出去

POJ 2812 恼人的青蛙 - 图2

如下图所示,可能会有多只青蛙从稻田穿越。青蛙的每一跳都恰好踩在一棵水稻上,将这棵水稻拍倒。有些水稻可能被多只青蛙踩踏。当然,农民所见到的是图4中的情形,并看不到图3中的直线,也见不到别人家田里被踩踏的水稻。

POJ 2812 恼人的青蛙 - 图3

构造出青蛙穿越稻田时的行走路径,并且只关心那些在穿越稻田时至少踩踏了3棵水稻的青蛙。因此,每条青蛙行走路径上至少包括3棵被踩踏的水稻。而在一条青蛙行走路径的直线上,也可能会有些被踩踏的水稻不属于该行走路径

  1. 不是一条行走路径:只有两棵被踩踏的水稻;
  2. 是一条行走路径,但不包括(2,6)上的水道;
  3. 不是一条行走路径:虽然有3棵被踩踏的水稻,但这三棵水稻之间的距离间隔不相等。

请你写一个程序,确定:在一条青蛙行走路径中,最多有多少颗水稻被踩踏。例如,图4的答案是7,因为第6行上全部水稻恰好构成一条青蛙行走路径。

输入

从标准输入设备上读入数据。第一行上两个整数R、C,分别表示稻田中水稻的行数和列数,1≤R、C≤5000。第二行是一个整数N,表示被踩踏的水稻数量, 3≤N≤5000。在剩下的N行中,每行有两个整数,分别是一颗被踩踏水稻的行号(1~R)和列号(1~C),两个整数用一个空格隔开。而且,每棵被踩踏水稻只被列出一次。

输出

从标准输出设备上输出一个整数。如果在稻田中存在青蛙行走路径,则输出包含最多水稻的青蛙行走路径中的水稻数量,否则输出0。

样例输入

  1. 6 7
  2. 14
  3. 2 1
  4. 6 6
  5. 4 2
  6. 2 5
  7. 2 6
  8. 2 7
  9. 3 4
  10. 6 1
  11. 6 2
  12. 2 3
  13. 6 3
  14. 6 4
  15. 6 5
  16. 6 7

样例输出

  1. 7

思路

我们枚举路径开始的2个点,由于两点确定一条直线,当开始的2个点被确定下来后,后面的很多因素也就被定下来了。

假设一只青蛙进入稻田后踩踏的前2个水稻分别是 POJ 2812 恼人的青蛙 - 图4#card=math&code=%28x_1%2C%20y_1%29)POJ 2812 恼人的青蛙 - 图5#card=math&code=%28x_2%2C%20y_2%29)

  • 青蛙下一跳的步长为:

    • X方向:POJ 2812 恼人的青蛙 - 图6
    • Y方向:POJ 2812 恼人的青蛙 - 图7
  • POJ 2812 恼人的青蛙 - 图8#card=math&code=%28x_1%20-%20dx%2C%20y_1%20-%20dy%29) 必须落在稻田外;
  • 当青蛙在水稻田某一位置POJ 2812 恼人的青蛙 - 图9#card=math&code=%28x%2C%20y%29)上时,下一跳踩踏的水稻坐标为:POJ 2812 恼人的青蛙 - 图10#card=math&code=%28x%20%2B%20dx%2C%20y%20%2B%20dy%29)
  • 将路径上的最后一棵水稻记作 POJ 2812 恼人的青蛙 - 图11#card=math&code=%28x_k%2C%20y_k%29),POJ 2812 恼人的青蛙 - 图12#card=math&code=%28x_k%20%2B%20dx%2C%20y_k%20%2B%20dy%29) 需要落在稻田之外.

枚举的过程我们这样操作:

  • 从输入的水稻中任取2棵,作为一只青蛙进入水稻后踩踏的前2棵水稻,看能否形成一条穿越稻田的路径

为了降低搜索空间,我们需要排除错误的答案。猜测 POJ 2812 恼人的青蛙 - 图13#card=math&code=%28X_1%2C%20Y_1%29)POJ 2812 恼人的青蛙 - 图14#card=math&code=%28X_2%2C%20Y_2%29)

  1. 青蛙不能经过一跳从稻田外跳到 POJ 2812 恼人的青蛙 - 图15#card=math&code=%28X_1%2C%20Y_1%29)上;
  2. 按照 POJ 2812 恼人的青蛙 - 图16#card=math&code=%28X_1%2C%20Y_1%29), POJ 2812 恼人的青蛙 - 图17#card=math&code=%28X_2%2C%20Y_2%29) 确定的步长,从 POJ 2812 恼人的青蛙 - 图18#card=math&code=%28X_1%2C%20Y_1%29) 出发,青蛙最多经过 POJ 2812 恼人的青蛙 - 图19#card=math&code=%28MAXSTEPS%20-%201%29) 步,就会跳到稻田之外, 其中 POJ 2812 恼人的青蛙 - 图20 是当前已经找到的最好答案.

我们用面向对象的类来描述一个坐标点,并借助C++提供的函数来帮助我们简化代码。

代码

样例数据能得到答案,但是不知道为什么POJ没过。。。。

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. class Plant {
  5. public:
  6. int x, y;
  7. };
  8. Plant plants[5001];
  9. int row = 0, col = 0, totalRice;
  10. int searchPath(Plant secarchPlant, int dx, int dy) {
  11. /* 判断从 searchPlant 开始,步长为 dx, dy, 那么最多能走几步 */
  12. Plant myPlant;
  13. myPlant.x = secarchPlant.x + dx;
  14. myPlant.y = secarchPlant.y + dy;
  15. int step = 2;
  16. while( myPlant.x <= row && myPlant.x >= 1 && myPlant.y <= col && myPlant.y >= 1 ) {
  17. if( !binary_search(plants, plants + totalRice, myPlant) ) {
  18. step = 0;
  19. break;
  20. }
  21. myPlant.x += dx;
  22. myPlant.y += dy;
  23. step++;
  24. }
  25. return step;
  26. }
  27. bool operator < (const Plant& p1, const Plant& p2) { // 配合sort函数
  28. if( p1.x == p2.x ) return p1.y < p2.y;
  29. return p1.x < p2.x;
  30. }
  31. int main() {
  32. cin >> row >> col >> totalRice;
  33. for(int i = 0; i < totalRice; i++)
  34. cin >> plants[i].x >> plants[i].y;
  35. // 将水稻按x坐标从小到大排序, x坐标相同按y从小到大排序
  36. sort(plants, plants + totalRice);
  37. // 枚举每一个点
  38. int max = 0, steps = 0;
  39. for(int i = 0; i < totalRice - 2; i++) { // plants[i]是第一个点
  40. for(int j = i + 1; j < totalRice - 1; j++) { // plant[j]是第二个点
  41. int dx = plants[j].x - plants[i].x;
  42. int dy = plants[j].y - plants[i].y;
  43. int previousX = plants[i].x - dx;
  44. int previousY = plants[i].y - dy;
  45. if(previousX <= row && previousX >= 1 && previousY <= col && previousY >= 1)
  46. continue; // 第2个点选的不合适
  47. if( plants[i].x + (max - 1) * dx > row )
  48. break; // 第1个点选的不合适
  49. previousY = plants[i].y + (max - 1) * dy;
  50. if( previousY > col || previousY < 1 )
  51. continue; // Y方向过早越界
  52. steps = searchPath(plants[j], dx, dy);
  53. if(steps > max) max = steps;
  54. }
  55. }
  56. if( max == 2) cout << 0 << endl;
  57. else cout << max << endl;
  58. return 0;
  59. }