感觉做完没什么进步,不会做的题就去搜题解,没过的题就去找数据。。。下次不能这样!
计算几何我觉得一靠板子,二靠细节。我会在另一篇博客整理出比较好的板子。细节得要自己培养培养,总不能总看网上的数据来过题呀。
C - Segments
题目大意:给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。
解题思路:如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条线和所有线段相交.
直线肯定经过两个端点。
枚举端点,判断直线和线段是否相交。
细节要注意,判断重合点。
还有就是加入只有一条线段的话,刚好直线是过同一条直线的。
所以保险的做法是枚举所有的两个端点,包括同一条直线的。(kuangbin的题解)
枚举端点是个常见的思路,往往端点就是极端情况。。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<set>
using namespace std;
const double eps = 1e-8;
struct point
{
int index;
double ang;
double x, y;
point() { x = 0;y = 0; }
point(double sx, double sy) { x = sx, y = sy; }
bool operator<(const point &b)const
{
if (x != b.x)return x < b.x;
return y < b.y;
}
};
struct line
{
double ang;
point a, b;line(){}
line(const point &p1, const point &p2)
{
a = p1;
b = p2;
}
};
double xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int opposite_side(point p1, point p2,line l)
{
double tmp = xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b);
return tmp < -eps || tmp < eps;
}
set<point>S;
line lines[105];
int n;
bool check(line a)
{
for (int i = 1;i <= n;i++)
{
point tmp1 = lines[i].a;
point tmp2 = lines[i].b;
if (!opposite_side(tmp1, tmp2, a))
return 0;
}
return 1;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
S.clear();
scanf("%d", &n);
double x1, y1, x2, y2;
for (int i = 1;i <= n;i++)
{
scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
S.insert(point(x1, y1));
S.insert(point(x2, y2));
lines[i] = line(point(x1, y1), point(x2, y2));
}
set<point>::iterator itor,itor2;
bool flag = false;
for(itor=S.begin();itor!=S.end();itor++)
for (itor2 = itor;itor2 != S.end();itor2++)
{
if (itor2 == itor)continue;
line tmp = line(*itor, *itor2);
if (check(tmp))
{
flag = true;
puts("Yes!");
itor = S.end();
itor--;
break;
}
}
if (!flag)
puts("No!");
}
}
E - The Doors
这题应该能做出来的,当时蠢了一下。。先计算出端点到其他能到的点的距离,然后跑最短路就行了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<queue>
using namespace std;
#define eps 1e-8
#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))
#define zero(x) (fabs(x)<eps)
struct point
{
int index;
double x, y;
point() { x = 0, y = 0; }
point(double sx, double sy)
{
x = sx;
y = sy;
}
};
struct line
{
point a, b;
line() {}
line(const point &p1, const point &p2)
{
a = p1;
b = p2;
}
};
vector<line>V;
double xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int opposite_side(point p1, point p2, line l)
{
return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) < -eps;
}
int intersect_ex(line u, line v)
{
return opposite_side(u.a, u.b, v) && opposite_side(v.a, v.b, u);
}
int parallel(line u, line v)
{
return zero((u.a.x - u.b.x)*(v.a.y - v.b.y) - (v.a.x - v.b.x)*(u.a.y - u.b.y));
}
double dist(line a)
{
double x = a.a.x - a.b.x;
double y = a.a.y - a.b.y;
return sqrt(x*x + y*y);
}
point P[100];
int pcnt;
double map[100][100];
void buildmap()
{
for(int i=1;i<=pcnt;i++)
for (int j = i + 1;j <= pcnt;j++)
{
map[i][j] = map[j][i] = 50.0;
line tmp = line(P[i], P[j]);
bool flag = true;
for (int k = 0;k < V.size();k++)
{
line tmp2 = V[k];
if (parallel(tmp, tmp2))continue;
if (intersect_ex(tmp, tmp2))
{
flag = false;
break;
}
}
if (flag)
map[i][j] = map[j][i] = dist(tmp);
}
}
bool vis[100];
double d[100];
struct HeapNode
{
int u;
double d;
HeapNode(int _u,double _d):u(_u),d(_d){}
HeapNode(){}
bool operator<(const HeapNode &b)const
{
return d > b.d;
}
};
double dijkstra()
{
memset(vis, 0, sizeof(vis));
for (int i = 1;i <= pcnt;i++)d[i] = 50;
d[1] = 0;
priority_queue<HeapNode>Q;
Q.push(HeapNode(1,d[1]));
while (!Q.empty())
{
HeapNode x = Q.top();Q.pop();
if (vis[x.u])continue;
vis[x.u] = 1;
for (int i = 1;i <= pcnt;i++)if(map[x.u][i]!=50)
{
if (d[i] > d[x.u] + map[x.u][i])
{
d[i] = d[x.u] + map[x.u][i];
Q.push(HeapNode(i, d[i]));
}
}
}
return d[2];
}
int main()
{
int n;
while (~scanf("%d", &n) && n != -1)
{
pcnt = 0;
V.clear();
double tmp1, tmp2, tmp3;
//line tmp;
P[++pcnt] = point(0, 5);
P[++pcnt] = point(10, 5);
for (int i = 1;i <= n;i++)
{
scanf("%lf %lf", &tmp1, &tmp2);
//P[++pcnt] = point(tmp1, 0);
P[++pcnt] = point(tmp1, tmp2);
V.push_back(line(point(tmp1, 0), point(tmp1, tmp2)));
scanf("%lf %lf", &tmp2, &tmp3);
P[++pcnt] = point(tmp1, tmp2);
P[++pcnt] = point(tmp1, tmp3);
V.push_back(line(point(tmp1, tmp2), point(tmp1, tmp3)));
scanf("%lf", &tmp2);
P[++pcnt] = point(tmp1, tmp2);
V.push_back(line(point(tmp1, tmp2), point(tmp1, 10)));
}
buildmap();
printf("%.2f\n", dijkstra());
}
}
G - Treasure Hunt
这题一开始我的思路想着把它转换成最短路,不同的房间如果隔着一个墙就连条边,然后和最外面的再连一条边,这样就可以求最短路了。但想了很久不知道怎么划分房间。。
正解还是枚举端点,端点和终点相连的线段看与多少个墙相交(不包括端点)。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
using namespace std;
#define eps 1e-5
struct point
{
double x, y;
point() { x = 0, y = 0; }
point(double sx, double sy)
{
x = sx;
y = sy;
}
}P[100];
int now;
struct line
{
point a, b;
line(){}
line(point p1, point p2)
{
a = p1;
b = p2;
}
}lines[35];
double aimx, aimy;
int n;
double xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int opposite_side(point p1, point p2, line l)
{
return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) < -eps;
}
int intersect_ex(line u, line v)
{
return opposite_side(u.a, u.b, v) && opposite_side(v.a, v.b, u);
}
void solve()
{
if (n == 0) { printf("Number of doors = 1\n");return; }
int ans = 35;
point aim = point(aimx, aimy);
for (int i = 1;i <= now;i++)
{
line tmp = line(P[i], aim);
int ctch = 0;
for (int j = 1;j <= n;j++)
{
if (intersect_ex(tmp, lines[j]))
ctch++;
}
ans = min(ans, ctch);
}
printf("Number of doors = %d\n", ans+1);
}
int main()
{
scanf("%d", &n);
int x1, y1, x2, y2;
now = 0;
for (int i = 1;i <= n;i++)
{
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
P[++now] = point(x1, y1);
P[++now] = point(x2, y2);
lines[i] = line(P[now - 1], P[now]);
}
scanf("%lf %lf", &aimx, &aimy);
solve();
}
H - Intersection
本专题傻题之一。题目挺简单的,但这题有几个坑点。
1,给出的矩形的两个点并不一定是按照顺序给出的,需要自己判断。
2,线段在矩形内部也算相交(无语)。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
using namespace std;
#define eps 1e-5
#define zero(x) (fabs(x)<eps)
struct point
{
int x, y;
point() { x = 0, y = 0; }
point(int sx, int sy) { x = sx;y = sy; }
};
int xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
struct line
{
point a, b;
line() {}
line(point _a, point _b) :a(_a), b(_b) {}
};
int dots_inline(point p1, point p2, point p3)
{
return zero(xmult(p1, p2, p3));
}
int same_side(point p1, point p2, line l)
{
return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) > eps;
}
int dot_online_in(point p, line l)
{
return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}
int intersect_in(line u, line v)
{
if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int x1, y1, x2, y2;
int x3, y3, x4, y4;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
line a = line(point(x1, y1), point(x2, y2));
scanf("%d %d %d %d", &x3, &y3, &x4, &y4);
if (x3 > x4)swap(x3, x4);
if (y3 < y4)swap(y3, y4);
point a1 = point(x3, y3), a2 = point(x4, y3), a3 = point(x3, y4), a4 = point(x4, y4);
line l1 = line(a1, a2), l2 = line(a1, a3), l3 = line(a3, a4), l4 = line(a2, a4);
if (!intersect_in(a, l1) && !intersect_in(a, l2) && !intersect_in(a, l3) && !intersect_in(a, l4))
{
point tmp = a.a;
if (tmp.x<x4&&tmp.x>x3&&tmp.y<y3&&tmp.y>y4)
puts("T");
else
puts("F");
}
else
puts("T");
}
}
I - Space Ant
一开始的思路没错,但是样例都没过,就发现我对极角排序有一点错误的理解。叉积极角排序只能排不超过π范围的点,如果超过了就得先按照象限排,再叉积极角排序。
另外atan2那种排序方式范围是-π到π,换句话说就是从第三象限排(如果我没搞错的话)。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<math.h>
using namespace std;
#define eps 1e-5
#define zero(x) (fabs(x)<eps)
struct point
{
int index;
int x, y;
point(){}
point(int _x,int _y,int idx):x(_x),y(_y),index(idx){}
};
int xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
double dist(point a, point b)
{
double x = a.x - b.x;
double y = a.y - b.y;
return sqrt(x*x + y*y);
}
struct line
{
point a, b;
double ang;
line(point sa, point sb)
{
a = sa;
b = sb;
}
line(){}
bool operator<(const line &y)const
{
if (zero(ang - y.ang))
{
return dist(a, b) < dist(y.a, y.b);
}
return ang < y.ang;
}
void getang()
{
ang = atan2(-b.y + a.y, -b.x + a.x);
}
};
point P[105];
int N;
int ans[105];
int cnt;
point now;
bool cmp(const point &a, const point &b)
{
int tmp = xmult(a, b, now);
if (tmp == 0)
return dist(a, now) < dist(b, now);
return tmp > 0;
}
void solve(int themin)
{
cnt = 0;
now = point(0, themin,0);
for (int i = 1;i <= N;i++)
{
sort(P + i, P + N + 1,cmp);
ans[++cnt] = P[i].index;
now = P[i];
}
printf("%d", N);
for (int i = 1;i <= N;i++)
printf(" %d", ans[i]);
puts("");
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d", &N);
int idx, x, y;
int miny = 105;
for (int i = 1;i <= N;i++)
{
scanf("%d %d %d", &idx, &x, &y);
P[idx] = point(x, y,idx);
miny = min(miny, y);
}
solve(miny);
}
}
J - Kadj Squares
首先我们要求出所有正方形放的位置,由于题目给的正方形边长是个整数,那么它想x坐标必然是一个小数,所以这里有一个小技巧,就是把它的边长都默认乘
2–√
2
,那么它的x坐标就变成整数了。
如何求一个正方形的位置呢,我们可以枚举它之前放好的正方形,先假设它靠在这个正方形上,求出当前的x,然后找到一个最大的x就是他的位置啦。
求完位置后在看它左边的正方形把它遮住了多少,右边的正方形把它遮住了多少,在判断一下就行了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
using namespace std;
int B[55], L[55];
vector<int>V;
int main()
{
int n;
while (~scanf("%d",&n)&&n)
{
V.clear();
int tmp;
for (int i = 1;i <= n;i++)
{
scanf("%d", &tmp);
int x = tmp;
L[i] = tmp;
for (int j = 1;j < i;j++)
{
if (tmp >= L[j])
x = max(x, B[j] + L[j] + L[j]);
else
x = max(x, B[j] + tmp * 2);
}
B[i] = x;
}
int ans = 0;
for (int i = 1;i <= n;i++)
{
int Left=0, Right=B[i]+L[i];
for (int j = 1;j < i;j++)
{
int x = B[j] + L[j];
if (x >= B[i] - L[i])
Left = max(Left, x);
}
for (int j = i + 1;j <= n;j++)
{
int x = B[j] - L[j];
if (x <= B[i] + L[i])
Right = min(Right, x);
}
if (Left < Right)V.push_back(i);
}
for (int i = 0;i < V.size();i++)
{
printf("%d", V[i]);
if (i != V.size() - 1)printf(" ");
else
puts("");
}
//printf("%d\n", ans);
}
}
一道坑题,但不得不说它是道好题。需要判断的地方很多,希望读者自行判断。。
提一点最重要的地方,就是有可能上面的板子遮住了下面的板子,使得一点雨都就不住。
注意精度问题,用C++交。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<stdio.h>
using namespace std;
#define eps 1e-8
#define zero(x) (fabs(x)<eps)
struct point
{
double x, y;
point(double sx, double sy) { x = sx;y = sy; }
point(){}
};
struct line
{
point a, b;
double ang;
line(){}
line(point p1, point p2)
{
a = p1;b = p2;
}
void getang()
{
ang = atan2((b.y - a.y) , (b.x - a.x));
}
};
double xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int same_side(point p1, point p2, line l)
{
return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) > eps;
}
int dots_inline(point p1, point p2, point p3)
{
return zero(xmult(p1, p2, p3));
}
int dot_online_in(point p, line l)
{
return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}
int intersect_in(line u, line v)
{
if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}
point intersection(line u, line v)
{
point ret = u.a;
double t = ((u.a.x - v.a.x)*(v.a.y - v.b.y) - (u.a.y - v.a.y)*(v.a.x - v.b.x)) / ((u.a.x - u.b.x)*(v.a.y - v.b.y) - (u.a.y - u.b.y)*(v.a.x - v.b.x));
ret.x += (u.b.x - u.a.x)*t;
ret.y += (u.b.y - u.a.y)*t;
return ret;
}
double area_triangle(point p1, point p2, point p3)
{
return fabs(xmult(p1, p2, p3)) / 2;
}
int parallel(line u, line v)
{
return zero((u.a.x - u.b.x)*(v.a.y - v.b.y) - (v.a.x - v.b.x)*(u.a.y - u.b.y));
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
double x1, y1, x2, y2, x3, y3, x4, y4;
scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
point p1 = point(x1, y1), p2 = point(x2, y2), p3 = point(x3, y3), p4 = point(x4, y4);
if (p1.y < p2.y)
swap(p1, p2);
if (p3.y < p4.y)
swap(p3, p4);
if (p1.y > p3.y)
{
swap(p1, p3);
swap(p2, p4);
}
line a = line(p1, p2);
line b = line(p3, p4);
a.getang();b.getang();
if (p1.x < p2.x&&p3.x<p4.x)
{
if (a.ang > b.ang&&p3.x<=p1.x)
{
puts("0.00");
continue;
}
}
if (p1.x > p2.x&&p3.x > p4.x)
{
if (a.ang < b.ang&&p3.x>=p1.x)
{
puts("0.00");
continue;
}
}
if (intersect_in(a, b))
{
if (zero(a.ang - b.ang))puts("0.00");
else
{
point insec1 = intersection(a, b);
line c = line(p1, point(p1.x+5, p1.y));
if (parallel(c, b))
puts("0.00");
else
{
point insec2 = intersection(c, b);
printf("%.2f\n", area_triangle(insec1, insec2, p1));
}
}
}
else
puts("0.00");
}
}
L - Pipe
此题初看可能十分困难,但是上下顶点对于限制光线非常关键。首先,我们想到如果一根光线自始至终未曾擦到任何顶点,肯定不是最优的(可以通过平移使之优化)。然后,如果只碰到一个顶点,那也不是最优的,可以通过旋转使他碰到另一个顶点,并且更优,最后要说明,最优光线必然是擦到一个上顶点和一个下顶点。以上三步的证明用反证法并不困难。所以留给读者。
于是有了一个简单的算法,任取一个上顶点和下顶点,形成直线l。若l能射穿左入口,即当x=x0时,直线l在(x0,y0)和(x0,y0-1)之间,则是一条可行光线。再从左到右依次判断每条上,下管壁是否与l相交,相交则求交点,并把交点x与当前最佳值比较,若所有管壁都不与l相交,说明l射穿了整个管道。(算法艺术与信息学竞赛)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<stdio.h>
using namespace std;
#define eps 1e-5
#define zero(x) (fabs(x)<eps)
#define inf 1e10
int sgn(double x)
{
if (fabs(x) < eps)return 0;
if (x < 0)return -1;
return 1;
}
struct point
{
double x, y;
point(double sx, double sy)
{
x = sx;
y = sy;
}
point(){}
}up[50],dwn[50];
struct line
{
point a, b;
line(point sa, point sb)
{
a = sa;
b = sb;
}
line(){}
}L[50];
double xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int opposite_side(point p1, point p2, line l)
{
return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) < -eps;
}
int intersect_ex(line u, line v)
{
return opposite_side(u.a, u.b, v) && opposite_side(v.a, v.b, u);
}
int same_side(point p1, point p2, line l)
{
double tmp= xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b);
cout << tmp << endl;
cout << (tmp > eps) << endl;
return tmp > eps;
}
int dots_inline(point p1, point p2, point p3)
{
return zero(xmult(p1, p2, p3));
}
int dot_online_in(point p, line l)
{
return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}
int intersect_in(line u, line v)
{
if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}
int n;
double dist(point a, point b)
{
double x = a.x - b.x;
double y = a.y - b.y;
return sqrt(x*x + y*y);
}
point intersection(line u, line v)
{
point ret = u.a;
double t = ((u.a.x - v.a.x)*(v.a.y - v.b.y) - (u.a.y - v.a.y)*(v.a.x - v.b.x)) / ((u.a.x - u.b.x)*(v.a.y - v.b.y) - (u.a.y - u.b.y)*(v.a.x - v.b.x));
ret.x += (u.b.x - u.a.x)*t;
ret.y += (u.b.y - u.a.y)*t;
return ret;
}
int Seg_inter_line(line l1, line l2)//判断直线l1和线段l2是否相交
{
double tmp1 = xmult(l2.a, l1.a, l1.b);
double tmp2 = xmult(l2.b, l1.a, l1.b);
return sgn(tmp1)*sgn(tmp2) <= 0;
}
void solve()
{
line first = line(up[1], dwn[1]);
double ans = -inf;
for(int i=1;i<=n;i++)
for (int j = 1;j <= n;j++)
{
line it = line(up[i], dwn[j]);
if (Seg_inter_line(it,first))
{
for (int k = 1;k <= n;k++)
{
line now = line(up[k], dwn[k]);
if (!Seg_inter_line(it, now))
{
line tmp1 = line(up[k], up[k - 1]);
line tmp2 = line(dwn[k], dwn[k - 1]);
if (Seg_inter_line(it, tmp1))
{
point t = intersection(it, tmp1);
ans = max(ans, t.x);
}
if (Seg_inter_line(it, tmp2))
{
point t = intersection(it, tmp2);
ans = max(ans, t.x);
}
break;
}
if (k == n)
{
ans = up[n].x + 1;
}
}
}
}
if (zero(ans - up[n].x-1))
puts("Through all the pipe.");
else
printf("%.2f\n", ans);
}
int main()
{
while (~scanf("%d",&n)&&n)
{
double x, y;
for (int i = 1;i <= n;i++)
{
scanf("%lf %lf", &x, &y);
up[i] = point(x, y);
dwn[i] = point(x, y - 1);
}
solve();
}
}
M - Geometric Shapes
本专题最傻的题。本来不想贴的,但感觉代码写的太好了,所以贴上来。。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<vector>
#include<string>
#include<math.h>
using namespace std;
#define eps 1e-5
#define zero(x) (fabs(x)<eps)
const double pi = acos(-1);
struct point
{
double x, y;
point(double sa, double sb)
{
x = sa;
y = sb;
}
point() {}
bool operator<(const point &b)const
{
if (x != b.x)
return x < b.x;
return y < b.y;
}
};
struct line
{
char s;
point a, b;
line(point sa, point sb, char ss)
{
a = sa;
b = sb;
s = ss;
}
line() {}
};
line L[1000];
int lcnt;
point rotate(point v, point p, double angle)
{
point ret = p;
v.x -= p.x, v.y -= p.y;
p.x = cos(angle);
p.y = sin(angle);
ret.x += v.x*p.x - v.y*p.y;
ret.y += v.x*p.y + v.y*p.x;
return ret;
}
void reads(char s)
{
char tmp1[50], tmp2[50];
scanf("%s %s", tmp1, tmp2);
int x1, y1, x2, y2;
sscanf(tmp1, "(%d,%d)", &x1, &y1);
sscanf(tmp2, "(%d,%d)", &x2, &y2);
point p1 = point(x1, y1);
point p2 = point(x2, y2);
point p3, p4;
point mid = point((x1 + x2 + 0.0) / 2.0, (y1 + y2 + 0.0) / 2.0);
p3 = rotate(p1, mid, pi / 2);
p4 = rotate(p1, mid, -pi / 2);
L[++lcnt] = line(p1, p3, s);
L[++lcnt] = line(p1, p4, s);
L[++lcnt] = line(p2, p3, s);
L[++lcnt] = line(p2, p4, s);
}
void readr(char s)
{
char tmp1[50], tmp2[50], tmp3[50];
scanf("%s %s %s", tmp1, tmp2, tmp3);
int x1, y1, x2, y2, x3, y3;
sscanf(tmp1, "(%d,%d)", &x1, &y1);
sscanf(tmp2, "(%d,%d)", &x2, &y2);
sscanf(tmp3, "(%d,%d)", &x3, &y3);
point p[4];
p[0] = point(x1, y1);
p[1] = point(x2, y2);
p[2] = point(x3, y3);
p[3] = point(p[2].x + (p[0].x - p[1].x), p[2].y - (p[1].y - p[0].y));
L[++lcnt] = line(p[0], p[1], s);
L[++lcnt] = line(p[1], p[2], s);
L[++lcnt] = line(p[2], p[3], s);
L[++lcnt] = line(p[0], p[3], s);
}
void readl(char s)
{
char tmp1[50], tmp2[50];
scanf("%s %s", tmp1, tmp2);
int x1, y1, x2, y2;
sscanf(tmp1, "(%d,%d)", &x1, &y1);
sscanf(tmp2, "(%d,%d)", &x2, &y2);
point a = point(x1, y1);
point b = point(x2, y2);
L[++lcnt] = line(a, b,s);
}
void readt(char s)
{
char tmp1[50], tmp2[50], tmp3[50];
scanf("%s %s %s", tmp1, tmp2, tmp3);
int x1, y1, x2, y2, x3, y3;
sscanf(tmp1, "(%d,%d)", &x1, &y1);
sscanf(tmp2, "(%d,%d)", &x2, &y2);
sscanf(tmp3, "(%d,%d)", &x3, &y3);
point a = point(x1, y1);
point b = point(x2, y2);
point c = point(x3, y3);
L[++lcnt] = line(a, b,s);
L[++lcnt] = line(a, c,s);
L[++lcnt] = line(b, c,s);
}
void readp(char s)
{
int num;
scanf("%d", &num);
int x1, y1;
char tmp1[50];
scanf("%s", tmp1);
sscanf(tmp1, "(%d,%d)", &x1, &y1);
int beforex = x1, beforey = y1;
int nowx, nowy;
for (int i = 2;i <= num;i++)
{
scanf("%s", tmp1);
sscanf(tmp1, "(%d,%d)", &nowx, &nowy);
L[++lcnt] = line(point(beforex, beforey), point(nowx, nowy),s);
beforex = nowx;
beforey = nowy;
}
L[++lcnt] = line(point(x1, y1), point(nowx, nowy), s);
}
bool col[30][30];
bool have[30];
bool read(char s, bool change)
{
if (change)
{
lcnt = 0;
memset(col, 0, sizeof(col));
memset(have, 0, sizeof(have));
}
char str[5];
scanf("%s", str);
if (str[0] == s)return 0;
have[str[0] - 'A'] = 1;
string type;
cin >> type;
if (type[0] == 's')
reads(str[0]);
else if (type[0] == 'r')
readr(str[0]);
else if (type[0] == 'l')
readl(str[0]);
else if (type[0] == 't')
readt(str[0]);
else if (type[0] == 'p')
readp(str[0]);
return 1;
}
double xmult(point p1, point p2, point p0)
{
return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}
int dots_inline(point p1, point p2, point p3)
{
return zero(xmult(p1, p2, p3));
}
int same_side(point p1, point p2, line l)
{
return xmult(l.a, p1, l.b)*xmult(l.a, p2, l.b) > eps;
}
int dot_online_in(point p, line l)
{
return zero(xmult(p, l.a, l.b)) && (l.a.x - p.x)*(l.b.x - p.x) < eps && (l.a.y - p.y)*(l.b.y - p.y) < eps;
}
int intersect_in(line u, line v)
{
if (!dots_inline(u.a, u.b, v.a) || !dots_inline(u.a, u.b, v.b))
return !same_side(u.a, u.b, v) && !same_side(v.a, v.b, u);
return dot_online_in(u.a, v) || dot_online_in(u.b, v) || dot_online_in(v.a, u) || dot_online_in(v.b, u);
}
int check(int num,int &flag)
{
int cnt = 0;
for (int i = 0;i < 26;i++)if (col[num][i])cnt++;
if (cnt == 1)
flag = 1;
else if (cnt == 2)
flag = 2;
else flag = 3;
for (int i = 25;i >= 0;i--)if (col[num][i])
return i;
return -1;
}
void solve()
{
for(int i=1;i<=lcnt;i++)
for (int j = i + 1;j <= lcnt;j++)if(L[i].s!=L[j].s)
{
if (intersect_in(L[i], L[j]))
{
col[L[i].s-'A'][L[j].s-'A'] = col[L[j].s-'A'][L[i].s-'A'] = 1;
}
}
for (int i = 0;i < 26;i++)if (have[i])
{
printf("%c", 'A' + i);
int flag;
int last = check(i,flag);
if (last==-1)
puts(" has no intersections");
else
{
printf(" intersects with");
if (flag == 1)
{
printf(" %c\n", last + 'A');
}
else if (flag == 2)
{
for (int j = 0;j <= last;j++)
{
if (!col[i][j])
continue;
char tmp = j + 'A';
if (j != last)
printf(" %c", tmp);
else
printf(" and %c\n", tmp);
}
}
else
{
for (int j = 0;j <= last;j++)
{
if (!col[i][j])
continue;
char tmp = j + 'A';
if (j != last)
printf(" %c,", tmp);
else
printf(" and %c\n", tmp);
}
}
}
}
}
int main()
{
string name;
while (read('.', true))
{
while (read('-', false));
solve();
puts("");
}
}
N - A Round Peg in a Ground Hole
一道模板题。先用叉积判断是不是凸包,再判断圆心是否在多边形内部,再用距离判断多边形是否把圆包围。
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int MAXN = 1e3 + 7;
const double EPS = 1e-8;
const double oo = 1e10 + 7;
struct Point
{
double x, y;
Point(double x = 0, double y = 0) :x(x), y(y) {}
Point operator - (const Point &tmp)const {
return Point(x - tmp.x, y - tmp.y);
}
double operator ^(const Point &tmp)const {
return x*tmp.y - y*tmp.x;
}
double operator *(const Point &tmp)const {
return x*tmp.x + y*tmp.y;
}
};
double Dist(Point a, Point b)
{///两点间的距离
return sqrt((a - b)*(a - b));
}
int Sign(double t)
{
if (t > EPS)return 1;
if (fabs(t) < EPS)return 0;
return -1;///负数
}
struct Segment
{
Point S, E;
Segment(Point S = 0, Point E = 0) :S(S), E(E) {}
bool OnSeg(const Point &p)
{///点是否在线段上
if (Sign((S - E) ^ (p - E)) == 0)///共线
if (Sign((p.x - S.x)*(p.x - E.x)) <= 0)///位于线段的中间或者端点
if (Sign((p.y - S.y)*(p.y - E.y)) <= 0)
return true;
return false;
}
bool Inter(const Segment &tmp)
{///只考虑完全相交的情况
return Sign((S - E) ^ (tmp.S - E)) * Sign((S - E) ^ (tmp.E - E)) == -1;
}
Point NearPoint(const Point &p)
{///点到线段最近的点
Point res;
double r = ((E - S)*(p - S)) / ((E - S)*(E - S));
if (r > EPS && (1.0 - r) > EPS)
{///点在线段的投影在线段上
res.x = S.x + r * (E.x - S.x);
res.y = S.y + r * (E.y - S.y);
}
else
{///求离最近的端点
if (Dist(p, S) < Dist(p, E))
res = S;
else
res = E;
}
return res;
}
};
struct Poly
{
int N;
Point vertex[MAXN];
bool IsConvex()
{///判断是否是凸多边形,可以共线
int vis[3] = { 0 };
for (int i = 0; i<N; i++)
{///如果同时出现整数和负数,说明存在凹的
int k = Sign((vertex[(i + 1) % N] - vertex[i]) ^ (vertex[(i + 2) % N] - vertex[i]));
vis[k + 1] = 1;
if (vis[0] && vis[2])
return false;
}
return true;
}
int InPoly(const Point &Q)
{///判断点Q是否在多边形内,射线法,奇数在内,偶数在外
///在圆上返回0, 圆外-1, 圆内 1
Segment ray(Point(-oo, Q.y), Q);///构造射线的最远处
int cnt = 0;///统计相交的边数
for (int i = 0; i<N; i++)
{
Segment edge(vertex[i], vertex[(i + 1) % N]);
if (edge.OnSeg(Q) == true)
return 0;///点在边上
if (ray.OnSeg(vertex[i]) == true)
{///如果相交连接点,那么取y值小的点
if (vertex[(i + 1) % N].y - vertex[i].y > EPS)
cnt++;
}
else if (ray.OnSeg(vertex[(i + 1) % N]) == true)
{
if (vertex[i].y - vertex[(i + 1) % N].y > EPS)
cnt++;
}
else if (ray.Inter(edge) && edge.Inter(ray))
cnt++;
}
if (cnt % 2)
return 1;
else
return -1;
}
};
struct Circle
{
Point center;///圆心
double R;///半径
};
bool Find(Poly &a, Circle &c)
{///判断圆是否在多边形内
if (a.InPoly(c.center) == -1)
return false;///如果圆心在多边形外面
for (int i = 0; i<a.N; i++)
{
Segment edge(a.vertex[i], a.vertex[(i + 1) % a.N]);
double len = Dist(c.center, edge.NearPoint(c.center));
if (Sign(len - c.R) < 0)
return false;
}
return true;
}
int main()
{
Poly a;///定义多边形
Circle c;///定义圆
while (scanf("%d", &a.N) != EOF && a.N > 2)
{
scanf("%lf%lf%lf", &c.R, &c.center.x, &c.center.y);
for (int i = 0; i<a.N; i++)
scanf("%lf%lf", &a.vertex[i].x, &a.vertex[i].y);
if (a.IsConvex() == false)
printf("HOLE IS ILL-FORMED\n");
else if (Find(a, c) == false)
printf("PEG WILL NOT FIT\n");
else
printf("PEG WILL FIT\n");
}
return 0;
}
之后会把整理的模板贴上来。