本题关键:如何找到最少的路径。
刚刚做的一题计算几何时建图的,做到这道题,第一个想法就是建图,找最短路, 后来细想操作太多太繁琐,不好做, 所以放弃了,觉得应该有简单的做法。
思考很关键:从外围四个墙的某一个门进来,走到宝藏,最小走几个门,实际就是进门点和宝藏的连线goalLine穿过几个点。
证明不好证,但如果说明大体的思想其实挺简单的:思想有点像两点之间直线最短。不要去管纵横交错的小线段,只管一开始原始输入的线段,因为在正方形范围内,这些线段可以想象为无限长,进门的点和宝藏点中间横跨着k条直线(墙 ),你就无法绕过它们,只能穿过它们 ,你往左往右走都只会徒增加你要穿过的墙,就这最基本的k道墙你总是要穿过。
但这样做还是很麻烦,枚举每个中点毕竟还是很繁琐的,再仔细想想,能不能枚举每个边缘的端点呢,画了很多种情况,觉得应该还是可以的,敲了一遍, 结果 AC,哈哈;
思考真的狠关键,千万别偷懒,如果想偷懒,还不如不搞ACM,假如你做一道题,没有思路之前就不必敲键盘了,这会是无用功,思考真的很重要,毕竟算法和模板大家学的都是一样的。
View Code
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; #define eps 10e-8 struct point { double x, y; point(){} point(double xx, double yy) : x(xx), y(yy){} }; struct seg { point a, b; seg(){} seg(point aa, point bb) : a(aa), b(bb){} }s[36]; int n; point p[70],dest; int ans, cnt1, cnt2; double cross(point o, point p1, point p2)//叉积 { return (p1.x - o.x)*(p2.y - o.y) - (p1.y - o.y)*(p2.x -o.x); } bool seg_cross(seg s1, point p1, point p2)//判断两线段是否相交(b不考虑共线,本题不可能共线) { if(cross(s1.a, s1.b, p1)*cross(s1.a, s1.b, p2)< -eps &&cross(p1, p2, s1.a)*cross(p1, p2, s1.b) < -eps) return 1; return 0; } int main() { int i, j; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&s[i].a.x, &s[i].a.y, &s[i].b.x, &s[i].b.y); s[n+1] = seg(point(0, 0), point(0, 100)); s[n+2] = seg(point(100, 0), point(100, 100)); scanf("%lf%lf",&dest.x, &dest.y); ans = 770; for(i=1;i<=n+2;i++) { cnt1 = cnt2 = 1; for(j=1;j<=n;j++) { if(seg_cross(s[j], dest, s[i].a))cnt1++; if(seg_cross(s[j], dest, s[i].b))cnt2++; } ans = min(min(cnt1, cnt2), ans); } printf("Number of doors = %d\n", ans); } return 0; }