【POJ】3845-Fractal-旋转坐标

传送门:poj3845


题解

t = 折 线 总 长 起 点 到 终 点 的 直 线 距 离 t=\frac{折线总长}{起点到终点的直线距离} t=线线

一条线段迭代 d d d次后的长度就是原来的 t d t^d td倍。

考虑从 d − 1 d-1 d1逐层确定目标点所在的线段,迭代查找,需要记录坐标的放缩和旋转角度。

很卡精度!计算角的大小函数 cal() \text{cal()} cal()里面就把 / ( 2 ∗ A ∗ B ) /(2*A*B) /(2AB)写成了 / 2 / A / B /2/A/B /2/A/B,精度就被卡了!


代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#define sqr(x) (x*x)
typedef double db;
using namespace std;
const db eps=1e-8;
const int N=110;

int tk,n,d;
db t,sum,f,res,rat,xz,bs;

struct P{
   db x,y;
   P(db x_=0.0,db y_=0.0):x(x_),y(y_){};
   inline P operator +(const P&ky){return P(x+ky.x,y+ky.y);}
   inline P operator -(const P&ky){return P(x-ky.x,y-ky.y);}
   inline db operator ^(const P&ky){return x*ky.y-y*ky.x;}
   inline P operator *(const db&ky){return P(x*ky,y*ky);}
   inline P operator /(const db&ky){return P(x/ky,y/ky);}
   inline db sq(){return sqrt(x*x+y*y);}
   bool operator <(const P&ky)const{
   	 db a=atan2(y,x),b=atan2(ky.y,ky.x);
   	 return a!=b?a<b:x<ky.x;
   } 
}p[N],st;

inline db dist(P a,P b){return (a-b).sq();}

struct Line{
	P dir;db len,ag,rat;
	Line(){};
	Line(P st,P ed){dir=ed-st;len=dist(st,ed);}
}l[N];

inline int dcmp(db x){if(fabs(x)<eps) return 0;return x>0?1:-1;}
inline bool onlf(P a,P b,P c){return (dcmp((c-b)^(b-a))>-1);}

inline db cal(P a,P b){
    db A=a.sq(),B=b.sq();P c=b-a;
    return acos((a.x*a.x+a.y*a.y+b.x*b.x+b.y*b.y-c.x*c.x-c.y*c.y)/(A*B*2))*((a^b)>0?1:-1);
}

inline P rot(P a,db b)
{return P(a.x*cos(b)-a.y*sin(b),a.x*sin(b)+a.y*cos(b));}

int main(){
	int i;db len;
	for(scanf("%d",&tk);tk;--tk){
		sum=0.0;scanf("%d",&n);
		for(i=1;i<=n;++i) scanf("%lf%lf",&p[i].x,&p[i].y);
		for(bs=dist(p[1],p[n]),i=1;i<n;++i){
			l[i]=Line(p[i],p[i+1]);sum+=l[i].len;
			l[i].rat=l[i].len/bs;l[i].ag=cal(p[n]-p[1],p[i+1]-p[i]);
		}
		t=sum/bs;scanf("%d%lf",&d,&f);d--;
		for(bs=1.0,i=1;i<=d;++i) bs*=t;
		res=sum*bs*f;st=p[1];rat=1.0;xz=0;
		for(;d>=0;--d){
			for(i=1;i<n;++i){
			    len=l[i].len*rat*bs;
			    if(res-len<eps) break;res-=len;
			    st=st+(rot(l[i].dir,xz)*rat);
			}
			if(!d){
			    st=st+(rot(l[i].dir,xz)/l[i].len*res);
			    printf("(%.10f,%.10f)\n",st.x,st.y);
		    }
		    bs/=t;xz+=l[i].ag;rat*=l[i].rat;
		}
		
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值