这个题。。无语啦。
好吧。
第一反应,建图,最短路。想了想,时间可能有点卡。写了好长。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;
}