1074: [SCOI2007]折纸origami
Submit: 372 Solved: 229
[Submit][Status][Discuss]
Description
桌上有一张边界平行于坐标轴的正方形纸片,左下角的坐标为(0,0),右上角的坐标为(100,100)。接下来执行
n条折纸命令。每条命令用两个不同点P1(x1,y1)和P2(x2,y2)来表示,执行时把当前的折纸作品沿着P1P2所在直线
折叠,并把有向线段P1P2的右边折向左边(左边的部分保持不变)。折叠结束后,需要在作品上打一个孔,然后用
绳子穿起来挂在墙上。孔的位置是相当重要的:若需要穿过太多层的纸,打孔本身比较困难;若穿过的层数太少,
悬挂起来以后作品可能会被撕破。为了选择一个比较合适的打孔位置,你需要计算在每个候选位置打孔时穿过的层
数。如果恰好穿过某一层的边界(误差0.000001内),则该层不统计在结果中。本题考虑一个简化的模型:纸的厚
度不计,因此折纸操作总能完美执行。
Input
输入第一行为一个整数n,即折纸的次数。以下n行每行四个实数x1,y1,x2,y2,表示每次折纸时对应的有向线
段。下一行包含一个正整数m,即候选位置的个数,以下每行包含两个实数x,y,表示一个候选位置。0<=n<=8, 1<=
m<=50
Output
每个候选位置输出一行,包含一个整数,即该位置打孔时穿过的层数。
Sample Input
2
-0.5 -0.5 1 1
1 75 0 75
6
10 60
80 60
30 40
10 10
50 50
20 50
-0.5 -0.5 1 1
1 75 0 75
6
10 60
80 60
30 40
10 10
50 50
20 50
Sample Output
4
2
2
0
0
2
2
2
0
0
2
怒怼了几天计算几何,先挖坑
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 7 const double eps=1e-6; 8 9 struct Point 10 { 11 double x,y; 12 }P[100000]; 13 int n,m; 14 double X1[10],Y1[10],X2[10],Y2[10]; 15 16 bool cmp(Point A,Point B) 17 { 18 return (A.x==B.x)?A.y<B.y:A.x<B.x; 19 } 20 21 Point flex(double x,double y,int k) 22 { 23 double A,B,C,Z,X,Y; 24 A=Y1[k]-Y2[k]; 25 B=X2[k]-X1[k]; 26 C=Y2[k]*(X1[k]-X2[k])-X2[k]*(Y1[k]-Y2[k]); 27 Z=(A*x+B*y+C)/(A*A+B*B); 28 X=x-2*A*Z; 29 Y=y-2*B*Z; 30 return (Point){X,Y}; 31 } 32 33 int query(double x,double y) 34 { 35 int now,top=0; 36 P[++top]=(Point){x,y}; 37 for(int i=n;i>=1;i--) 38 { 39 now=top; 40 for(int j=1;j<=now;j++) 41 P[++top]=flex(P[j].x,P[j].y,i); 42 } 43 now=0; 44 sort(P+1,P+top+1,cmp); 45 for(int i=1;i<=top;i++) 46 if(P[i].x!=P[i-1].x||P[i].y!=P[i-1].y) 47 P[++now]=P[i]; 48 return now; 49 } 50 51 int main() 52 { 53 scanf("%d",&n); 54 for(int i=1;i<=n;i++) 55 { 56 scanf("%lf%lf%lf%lf",&X1[i],&Y1[i],&X2[i],&Y2[i]); 57 } 58 scanf("%d",&m); 59 for(int i=1;i<=m;i++) 60 { 61 double x,y; 62 scanf("%lf%lf",&x,&y); 63 printf("%d\n",query(x,y)); 64 } 65 return 0; 66 }