//25008K 1891MS G++
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
int W;
int H;
const int MAX = 5010;
struct Flatten {
int x;
int y;
};
typedef struct Flatten Flatten;
Flatten flattens[MAX];
char plant[MAX][MAX];
int flatternNum;
int cmp(const Flatten &a,const Flatten &b)
{
if(a.y==b.y)return a.x<b.x;
else return a.y<b.y;
}
int max1;
void getMax() {
max1 = 0;
for (int i = 1; i < flatternNum; i++) {
for (int j = i + 1; j <= flatternNum; j++) {
int disx = flattens[j].x - flattens[i].x;
int disy = flattens[j].y - flattens[i].y;
if (flattens[i].x - disx > 0 && flattens[i].x - disx <= W &&
flattens[i].y - disy > 0 && flattens[i].y - disy <= H) {
continue;
}
int cnt = 0;
int curX = flattens[j].x + disx;
int curY = flattens[j].y + disy;
while(curX > 0 && curX <= W &&
curY > 0 && curY <= H) {
cnt++;
if (!plant[curX][curY]) {
cnt = 0;
break;
}
curX += disx;
curY += disy;
}
max1 = max1 > cnt ? max1: cnt;
}
}
if (max1 >= 1) {
printf("%d\n", max1 +2);
} else {
printf("0\n");
}
}
int main() {
while(scanf("%d %d", &H, &W) != EOF) {
scanf("%d", &flatternNum);
memset(plant, 0, sizeof(plant));
for (int i = 1; i <= flatternNum; i++) {
int x, y;
scanf("%d %d", &y, &x);
flattens[i].x = x;
flattens[i].y = y;
plant[x][y] = 1;
}
sort(flattens, flattens + flatternNum, cmp);
getMax();
}
}
http://blog.csdn.net/lin375691011/article/details/26722325
http://gisyhy.blog.163.com/blog/static/1293903432009924102938864/
这道题让我发现自己现在的一个误区,过于重视那些具体化的优化算法,对枚举暴力这种最朴素的解法不屑一顾,其实是不应该的,某些时候,可能暴力枚举其实是最有效的,也和项目一样,有时候其实不care用了什么先进的编程思想或者语言架构(如果对后期扩展不是特别重视的话),只要可以解决问题即可,并且算法这方面,暴力枚举往往是所有高级算法诞生的基础,正是在朴素的暴力枚举的基础上,进行不断的优化和空间时间互换,才诞生了一些高级算法。
这道题就是暴力搜索+剪枝, 第二个链接其实给了用DP做的办法,不过也没提高太多,
暴力枚举的思路很简单,在题目给出的所有点里,任意找两个进行组合得到一条直线,比如 点i 和 点j,
然后对其进行check, 首先,很重要的一点, 多个点可能是在同一条直线上的, 比如 A B C D, 都在直线L上,那么 其实 组合 AB AC AD BC BD CD 所代表的直线都是一样的,如果对每种组合都做一次验证处理,那么必然TLE,并且这也是非常冗余的操作,也是第一个可以改进的点,对于A B C D这条直线, 可以只有A 和 B这两个 青蛙沿着该直线进入麦田的最前两个点来表示, 这样,其他的组合都可以被略掉,因为他们不是青蛙进入的最开始两个点,那么为了进行有效判断, 区分 A B 和 B A这两种排列,
事先要对输入的点进行一次排序: 第一比较按y坐标的大小,第二比较(如果y相等的话)按x坐标的大小,这样就可以解决AB BA的问题了,并且方向性也可以确定,
就假设青蛙是沿着从A到B的方向进入麦田的, 那么可以得每次hop x 和 y的递增值:disX = node[B].x - node[i].x , disY = node[B].y - node[i].y,
那么要判断A 是第一个进入的点,只需要满足:
node[A].x - disX < 0 或者 node[A].x - disX > W(麦田宽度, 这个check其实不需要,之前的排序保证了 disX的>=0)
node[A].y - disY <0 或者 node[A].x - disX > H(麦田高度, 同上)
这是第二次剪枝,
然后第三次剪枝:如果在这条直线的某个点的麦子没有被践踏(这个推荐用一个二维数组来标示践踏点,不会MLE,有人是将践踏点排序二分查找是否存在,跟hash比还是有些费时间),那么这条直线也是不存在的(一开始漏了这一条,题目说的也不是很清晰)
最终取符合条件的这些情况下点的最多的情况(如果最终<3, 那么还是0)