poj3845 Fractal 【坐标变换】

题目大意:

给一条折线,每一次操作把这条折线的所有线段变换成跟这条折线的相同形状,重复d次。问此时从头到尾走全长的f(0≤f≤1)倍,将停在哪个点上。

解题思路:

假设做了一次分形后得到折线长度是原来的 k 倍,则深度为d的分形(操作了d-1次)的长度是原来的kd1倍。若当前线段增长后已经超出了所剩余的长度,就确定终点在当前线段上,那么递归 kd2 ,确定下一层变换终点所在直线。
要注意每次变换后图形需要旋转和缩放,所以要预处理出每条线段的偏转角度。

ps:这道题卡精度卡到爆炸,double运算能少就少。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;

const int N=105;
const double eps=1e-8;
struct point
{
    double x,y;
    point(){}
    point(double _x,double _y):x(_x),y(_y){}
    inline friend point operator - (const point &a,const point &b)
    {return point(a.x-b.x,a.y-b.y);}
    inline friend point operator + (const point &a,const point &b)
    {return point(a.x+b.x,a.y+b.y);}
    inline friend point operator / (const point &a,const double &b)
    {return point(a.x/b,a.y/b);}
    inline friend point operator * (const point &a,const double &b)
    {return point(a.x*b,a.y*b);}
    inline friend double operator * (const point &a,const point &b)
    {return a.x*b.y-a.y*b.x;}
    inline double dis(){return sqrt(x*x+y*y);}
}p[N];
struct line
{
    point v;
    double len,ang,ratio;
    line(){}
    line(point st,point ed)
    {len=(ed-st).dis();v=ed-st;}
}l[N];
int T,n,d;
double k,f,rate,L;

double calc(point a,point b)
{
    return acos((a.x*b.x+a.y*b.y)/(a.dis()*b.dis()))*(a*b>0?1:-1);
}

point rotate(point a,double theta)
{
    return point(a.x*cos(theta)-a.y*sin(theta),a.x*sin(theta)+a.y*cos(theta));
}

void go(point s,double R,int dep,double theta,double ratio)
{
    for(int i=1;i<n;i++)
    {
        double len=l[i].len*ratio*R;
        if(L-len<eps)
        {
            if(dep)go(s,R/rate,--dep,theta+l[i].ang,ratio*l[i].ratio);
            else
            {
                s=s+rotate(l[i].v,theta)/l[i].len*L;
                printf("(%.10f,%.10f)\n",s.x,s.y);
            }
            return;
        }
        else L-=len,s=s+rotate(l[i].v,theta)*ratio;
    }
}

int main()
{
    //freopen("lx.in","r",stdin);
    //freopen("lx.out","w",stdout);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
        scanf("%d%lf",&d,&f);d--;
        k=0;
        for(int i=1;i<n;i++) 
        {
            k+=(p[i+1]-p[i]).dis();
            l[i]=line(p[i],p[i+1]);
            l[i].ratio=l[i].len/(p[n]-p[1]).dis();
            l[i].ang=calc(p[n]-p[1],p[i+1]-p[i]);
        }
        rate=k/(p[n]-p[1]).dis();
        double R=1; 
        for(int i=1;i<=d;i++)R*=rate;
        L=f*R*k;
        go(p[1],R,d,0,1);                                                                                                                            
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值