BZOJ 1074: [SCOI2007]折纸origami

1074: [SCOI2007]折纸origami

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 354  Solved: 212
[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

Sample Output

4
2
2
0
0
2

题解

对于每个询问,将点倒着操作一步步展开,判断最后有多少个存在的点即可。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=10;
const double eps=1e-6,inf=0x3f3f3f3f;
int n,m,ans;
struct point{
	double x,y;
	point operator-(point a){
		return (point){x-a.x,y-a.y};
	}
	double operator*(point a){
		return x*a.y-a.x*y;
	}
	bool operator==(point a)const{
		return (fabs(x-a.x)<eps&&fabs(y-a.y)<eps);
	} 
};
point no=(point){inf,inf},single=(point){-inf,-inf};
struct line{
	point s,t;
}l[N];
point turn(point a,line l){
	double fg=(l.t-l.s)*(a-l.s);
	if(fg>eps){
		point res;
		if(fabs(l.s.y-l.t.y)<eps){
			res.x=a.x,res.y=l.s.y*2-a.y;
		}
		else if(fabs(l.s.x-l.t.x)<eps){
			res.x=l.s.x*2-a.x,res.y=a.y;
		}
		else{
			double k1=(l.s.y-l.t.y)/(l.s.x-l.t.x),b1=l.s.y-k1*l.s.x;
			double k2=-1/k1,b2=a.y-k2*a.x;
			double x=(b2-b1)/(k1-k2),y=k1*x+b1;
			res.x=x*2-a.x,res.y=y*2-a.y;
		}
		return res;
	}
	return no;
}
void dfs(point a,int now){
	if(now==0){
		if(a.x>eps&&a.x<100-eps&&a.y>eps&&a.y<100-eps){
			ans++;
		}
		return;
	}
	point b=turn(a,l[now]);
	if(b==no)return;
	else{
		dfs(a,now-1);
		dfs(b,now-1);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lf%lf%lf%lf",&l[i].s.x,&l[i].s.y,&l[i].t.x,&l[i].t.y);
	}
	scanf("%d",&m);
	point q;
	for(int i=1;i<=m;i++){
		ans=0;
		scanf("%lf%lf",&q.x,&q.y);
		dfs(q,n);
		printf("%d\n",ans);
	}
	return 0;
}

转载于:https://www.cnblogs.com/chezhongyang/p/7763447.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值