poj-1054

22 篇文章 0 订阅
7 篇文章 0 订阅
//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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值