这个题。。无语啦。
好吧。
第一反应,建图,最短路。想了想,时间可能有点卡。写了好长。N^3的算法。跑了300+ms。。
看人家都是0ms,纠结啊。看了下discuss,见有提到直接判断交点个数!!!囧啊!!!
说的是啊。既然要通过门,那么肯定要通过这个线段的某一点,到达另外一个门。通过几个墙,那么就是经过几扇门到达另外一个点。
这样的话,直接枚举围墙的中点,求最多交点个数即可。
zoj也有这题,PE数次,惭愧。。
我的dijkstra建图。。我好伟大。。
#include <set> #include <map> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define FOR(i,s,t) for(int i=(s); i<(t); i++) #define BUG puts("here!!!") #define STOP system("pause") #define file_r(x) freopen(x, "r", stdin) #define file_w(x) freopen(x, "w", stdout) using namespace std; const int MAX = 40; const int MAX_N = MAX*MAX; const double eps = 1e-6; bool dy(double x,double y) { return x > y + eps;} // x > y bool xy(double x,double y) { return x < y - eps;} // x < y bool dyd(double x,double y) { return x > y - eps;} // x >= y bool xyd(double x,double y) { return x < y + eps;} // x <= y bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y struct point{ double x, y; point(){}; point(double xx, double yy):x(xx), y(yy){} bool operator==(const point &a) { return dd(x, a.x) && dd(y, a.y); } void get() { scanf("%lf%lf", &x, &y); } }; struct line{ point a, b; }; point l2l_inst_p(line l1,line l2) { point ans = l1.a; double t = ((l1.a.x - l2.a.x)*(l2.a.y - l2.b.y) - (l1.a.y - l2.a.y)*(l2.a.x - l2.b.x))/ ((l1.a.x - l1.b.x)*(l2.a.y - l2.b.y) - (l1.a.y - l1.b.y)*(l2.a.x - l2.b.x)); ans.x += (l1.b.x - l1.a.x)*t; ans.y += (l1.b.y - l1.a.y)*t; return ans; } double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正 { return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y); } bool onSegment(point a, point b, point c) { if( dd(crossProduct(a,b,c),0.0) && dyd(c.x,min(a.x,b.x)) && xyd(c.x,max(a.x,b.x)) && dyd(c.y,min(a.y,b.y)) && xyd(c.y,max(a.y,b.y)) ) return true; return false; } bool s2s_inst(point p1,point p2, point p3, point p4) { double d1 = crossProduct(p3,p4,p1); double d2 = crossProduct(p3,p4,p2); double d3 = crossProduct(p1,p2,p3); double d4 = crossProduct(p1,p2,p4); if( xy(d1 * d2,0.0) && xy(d3 * d4,0.0) ) return true; //如果不判端点相交,则下面这句话不需要 if( dd(d1,0.0) && onSegment(p3,p4,p1) || dd(d2,0.0) && onSegment(p3,p4,p2) || dd(d3,0.0) && onSegment(p1,p2,p3) || dd(d4,0.0) && onSegment(p1,p2,p4) ) return true; return false; } point p[MAX], t[MAX*MAX*MAX], s, lp[MAX][MAX*MAX]; line l[MAX]; int len[MAX]; bool a[MAX_N][MAX_N]; bool cmp(point a, point b) { if( dd(a.x, b.x) ) return xy(a.y, b.y); return xy(a.x, b.x); } bool check(point a, point b, int n) { FOR(i, 0, n) { if( onSegment(l[i].a, l[i].b, a) || onSegment(l[i].a, l[i].b, b) ) continue; if( s2s_inst(a, b, l[i].a, l[i].b) ) return false; } return true; } bool bian[MAX_N]; int Dijkstra(int from, int n) // DIJ + 邻接矩阵 { int dis[MAX_N]; bool used[MAX_N]; memset(used,false,sizeof(used)); for(int i=0; i<n; i++) dis[i] = INT_MAX; dis[from] = 0; used[from] = true; int now = from; for(int i=1; i<n; i++) { for(int k=0; k<n; k++) if( a[now][k] && dis[k] > dis[now] + 1 ) dis[k] = dis[now] + 1; int min = INT_MAX; for(int k=0; k<n; k++) if( !used[k] && dis[k] < min ) min = dis[now = k]; used[now] = true; } int min = INT_MAX; FOR(i, 0, n-1) if( bian[i] && dis[i] < min ) min = dis[i]; return min; } int solve( int n ) { memset(len, 0, sizeof(len)); memset(a, 0, sizeof(a)); memset(bian, 0, sizeof(bian)); int cnt = 0; FOR(i, 0, n) FOR(k, i+1, n) if( s2s_inst(l[i].a, l[i].b, l[k].a, l[k].b) ) lp[k][len[k]++] = lp[i][len[i]++] = l2l_inst_p(l[i], l[k]); FOR(i, 0, n) { sort(lp[i], lp[i]+len[i], cmp); FOR(k, 1, len[i]) { if( lp[k] == lp[k-1] ) continue; if( i >= n - 4 ) bian[cnt] = true; t[cnt++] = point((lp[i][k].x + lp[i][k-1].x)/2, (lp[i][k].y + lp[i][k-1].y)/2); } } t[cnt++] = s; FOR(i, 0, cnt) FOR(k, i+1, cnt) if( check(t[i], t[k], n) ) a[i][k] = a[k][i] = true; return Dijkstra(cnt-1, cnt); } int main() { int n; while( ~scanf("%d", &n) ) { FOR(i, 0, n) { l[i].a.get(); l[i].b.get(); } l[n].a = point(0, 0); l[n++].b = point(100, 0); l[n].a = point(100, 0); l[n++].b = point(100, 100); l[n].a = point(100, 100); l[n++].b = point(0, 100); l[n].a = point(0, 100); l[n++].b = point(0, 0); s.get(); int ans = solve(n); printf("Number of doors = %d\n", ans); } return 0; }
求交点个数的算法
#include <set> #include <map> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define FOR(i,s,t) for(int i=(s); i<(t); i++) #define BUG puts("here!!!") #define STOP system("pause") #define file_r(x) freopen(x, "r", stdin) #define file_w(x) freopen(x, "w", stdout) using namespace std; const int MAX = 40; const int MAX_N = MAX*MAX; const double eps = 1e-6; bool dy(double x,double y) { return x > y + eps;} // x > y bool xy(double x,double y) { return x < y - eps;} // x < y bool dyd(double x,double y) { return x > y - eps;} // x >= y bool xyd(double x,double y) { return x < y + eps;} // x <= y bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y struct point{ double x, y; point(){}; point(double xx, double yy):x(xx), y(yy){} bool operator==(const point &a) { return dd(x, a.x) && dd(y, a.y); } void get() { scanf("%lf%lf", &x, &y); } }; struct line{ point a, b; }; double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正 { return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y); } bool onSegment(point a, point b, point c) { if( dd(crossProduct(a,b,c),0.0) && dyd(c.x,min(a.x,b.x)) && xyd(c.x,max(a.x,b.x)) && dyd(c.y,min(a.y,b.y)) && xyd(c.y,max(a.y,b.y)) ) return true; return false; } bool s2s_inst(point p1,point p2, point p3, point p4) { double d1 = crossProduct(p3,p4,p1); double d2 = crossProduct(p3,p4,p2); double d3 = crossProduct(p1,p2,p3); double d4 = crossProduct(p1,p2,p4); if( xy(d1 * d2,0.0) && xy(d3 * d4,0.0) ) return true; //如果不判端点相交,则下面这句话不需要 if( dd(d1,0.0) && onSegment(p3,p4,p1) || dd(d2,0.0) && onSegment(p3,p4,p2) || dd(d3,0.0) && onSegment(p1,p2,p3) || dd(d4,0.0) && onSegment(p1,p2,p4) ) return true; return false; } point p[MAX], t[MAX*2], s; line l[MAX]; point C; bool cmp(point a,point b) { double t1 = atan2(a.y - C.y, a.x - C.x); double t2 = atan2(b.y - C.y, b.x - C.x); if( dd(t1, t2) ) return xy(fabs(a.x),fabs(b.x)); return xy(t1, t2); } bool cmp_equal(point a, point b) { return a == b; } int solve( int n ) { int cnt = 0; C = point(50, 50); FOR(i, 0, n) { t[cnt++] = l[i].a; t[cnt++] = l[i].b; } sort(t, t+cnt, cmp); cnt = unique(t, t+cnt, cmp_equal) - t; int min = INT_MAX; FOR(i, 1, cnt) { int door = 0; if( !(dd(t[i].x, t[i-1].x) || dd(t[i].y, t[i-1].y)) ) continue; point e = point((t[i].x + t[i-1].x)/2, (t[i].y + t[i-1].y)/2); FOR(k, 0, n) if( s2s_inst(s, e, l[k].a, l[k].b) ) door++; if( door == 0 ) BUG; if( door < min ) min = door; } return min; } int main() { int n; while( ~scanf("%d", &n) ) { FOR(i, 0, n) { l[i].a.get(); l[i].b.get(); } l[n].a = point(0, 0); l[n++].b = point(100, 0); l[n].a = point(100, 0); l[n++].b = point(100, 100); l[n].a = point(100, 100); l[n++].b = point(0, 100); l[n].a = point(0, 100); l[n++].b = point(0, 0); s.get(); int ans = solve(n); printf("Number of doors = %d\n", ans); } return 0; }