hdu - 3952 Fruit Ninja(简单几何)
思路来自于:http://www.cnblogs.com/wuyiqi/archive/2011/11/06/2238530.html
枚举两个多边形的两个点组成的直线,判断能与几个多边形相交
因为最佳的直线肯定可以经过某两个点(可以平移到顶点处),所以暴力枚举两个点就好了
如果有模版的话,写代码就快多了。代码如下:
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <string> #include <cmath> #include <queue> #include <stack> #include <vector> #include <map> #define LL long long #define eps 1e-8 #define N 15 #define K 15 using namespace std; struct Point{ double x, y; Point operator - (const Point &t) const { Point temp; temp.x = x-t.x; temp.y = y-t.y; return temp; } Point operator + (const Point &t) const { Point temp; temp.x = x+t.x; temp.y = y+t.y; return temp; } bool operator == (const Point &t) const { return fabs(x-t.x)<eps&&fabs(y-t.y)<eps; } }; struct Figure{ int cnt; Point poi[K]; }; struct Line{ double a, b, c; }; Figure fig[N]; Line t_Line(Point a, Point b)//点到直线的转化 { Line temp; temp.a = a.y-b.y; temp.b = b.x-a.x; temp.c = a.x*b.y-b.x*a.y; return temp; } bool Line_Inst(Line l1, Line l2, Point &p)//判断直线相交,并求交点 { double a1 = l1.a, b1 = l1.b, c1 = l1.c; double a2 = l2.a, b2 = l2.b, c2 = l2.c; if(fabs(a1*b2-a2*b1)<eps) return false; p.x = (b1*c2-b2*c1)/(a1*b2-a2*b1); p.y = (a1*c2-a2*c1)/(a2*b1-a1*b2); return true; } double cross(Point a, Point b, Point c)//求向量的叉积,判断三点是否共线 { return (b.x-c.x)*(a.y-c.y)-(b.y-c.y)*(a.x-c.x); } bool dotOnSeg(Point a, Point b, Point c)//判断点是否在线段上 { if(a==c||b==c) return true; return cross(a,b,c)<eps&& (b.x-c.x)*(a.x-c.x)<eps&& (b.y-c.y)*(a.y-c.y)<eps; } int main () { int t, n, k, kk = 0; scanf("%d", &t); while(t--) { scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d", &k); fig[i].cnt = k; for(int j = 1; j <= k; ++j) scanf("%lf %lf", &fig[i].poi[j].x, &fig[i].poi[j].y); } if(n<=2) { printf("Case %d: %d\n",++kk, n); continue; } int ans = 0; Point p; for(int i = 1; i <= n; ++i) for(int j = i+1; j <= n; ++j) for(int k = 1; k <= fig[i].cnt; ++k) for(int l = 1; l <= fig[j].cnt; ++l) { Line l1 = t_Line(fig[i].poi[k], fig[j].poi[l]);//找到经过两个图形的顶点的直线 int tt = 2; for(int ii = 1; ii <= n; ++ii) { if(ii==i||ii==j) continue; for(int jj = 1; jj < fig[ii].cnt; ++jj) { Line l2 = t_Line(fig[ii].poi[jj], fig[ii].poi[jj+1]);//图形的两个相邻节点组成一条直线 if(Line_Inst(l1,l2,p)&&dotOnSeg(fig[ii].poi[jj], fig[ii].poi[jj+1], p)) {//直线相交,并且交点位于线段上,即可证明直线l1穿过线段 ++tt; break; } } } ans = max(ans, tt); } printf("Case %d: %d\n",++kk, ans); } return 0; }