POJ 1054 The Troublesome Frog 枚举
这个题分类是dp,想了一会没有想出来,就去看别人题解了。发现别人题解全是暴力枚举= =。复杂度超过 N^2,但可能是剪枝的作用,没有超时。
思路:将所有点按坐标由小到大排序。两两枚举点p1,p2,并判断其中坐标较小的点p1是否是该路径上青蛙跳至的第一个点(假设在p1之前还有一点,则可以根据p1和p2的距离算出p1前一点的坐标,判断该坐标是否在麦田内,若不在则说明p1是青蛙跳至的第一个点)。判定p1前一点坐标时,我原以为由于所有点的坐标都是排好序的(从小到大),则p1前一点的坐标必然更小,因此判定它是否在麦田内时只需要判断是否坐标都大于0,并不需要判断是否超坐标上限。但这种思路是错误的。见下图。
上图情况中,排好序后两两枚举,则到点2与点3时,p1是点2,p2是点1,则p1的前一点在图中的虚线上,此时明显需要判断该点是否超过麦田的坐标上限。
通过上述判断规则,如果p1不是青蛙跳至的第一个点,则跳过该次枚举(因为它必然包含在某次枚举的情况里)。如果是,则根据p1到p2的坐标变化,判断p2后面所有要跳至的点是否都存在。如果存在,则该次枚举是有效的。记录该路径跳的次数。
最后求所有次数的最大值即可。
下面是代码:
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 #define maxn 5005 6 using namespace std; 7 struct nod 8 { 9 int x, y; 10 bool operator < (const nod &cmp) const 11 { 12 if (x == cmp.x) return y < cmp.y; 13 return x < cmp.x; 14 } 15 }rice[maxn]; 16 bool map[maxn][maxn]; 17 int main() 18 { 19 int r, c, n; 20 //freopen("data.in", "r", stdin); 21 scanf("%d%d%d",&r,&c,&n); 22 memset(map, 0, sizeof(map)); 23 for (int i = 0; i < n; i++) 24 { 25 scanf("%d%d",&rice[i].x, &rice[i].y); 26 map[rice[i].x][rice[i].y] = 1; 27 } 28 sort(rice, rice + n); 29 int res = 0; 30 for (int i = 0; i < n; i++) 31 for (int j = i + 1; j < n; j++) if (i != j) 32 { 33 int dx = rice[j].x - rice[i].x; 34 int dy = rice[j].y - rice[i].y; 35 if (rice[i].x - dx >= 1 && rice[i].x - dx <= r && rice[i].y - dy >= 1 && rice[i].y - dy <= c) continue; 36 int nx = rice[j].x + dx; 37 int ny = rice[j].y + dy; 38 int len = 2; 39 int ok = 1; 40 while (nx > 0 && nx <= r && ny > 0 && ny <= c && ok) 41 { 42 if (map[nx][ny]) len++; 43 else ok = 0; 44 nx += dx; 45 ny += dy; 46 } 47 if (ok && len > 2) res = max(res, len); 48 } 49 printf("%d", res); 50 return 0; 51 }