[poj][3845][Fractal]

题目:http://poj.org/problem?id=3845

题意:给一条折线,d次分形后,求一点到初始点的距离与总长度之比刚好为 f (0<=f<=1)的位置。(一开始有点搞不明白,后来才确定就是把起始点和结束点缩放到每一条边的端点上)

普通方法

View Code
#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>



#define sqr(x) ((x)*(x))

using namespace std;



const int N = 110;

const double eps = 1e-12;



struct cpoint{

    double x, y;

    void get(){scanf("%lf%lf", &x, &y);}

    void put(){printf("(%.7f,%.7f)\n", x, y);}

}cp[N];



int dcmp(double x){

    return x<-eps?-1:(x>eps);

}



double cross(cpoint o, cpoint p, cpoint q){

    return (p.x-o.x)*(q.y-o.y)-(p.y-o.y)*(q.x-o.x);

}



double dot(cpoint o, cpoint p, cpoint q){

    return (p.x-o.x)*(q.x-o.x)+(p.y-o.y)*(q.y-o.y);

}



double dis(cpoint p, cpoint q){

    return sqrt(sqr(p.x-q.x)+sqr(p.y-q.y));

}



double angle(cpoint o, cpoint p, cpoint q){

    double cr=cross(o,p,q), dt=dot(o,p,q);

    if (dcmp(cr)==0) cr=0;

    if (dcmp(dt)==0) dt=0;

    return atan2(cr,dt);

}



cpoint rotating(cpoint v,cpoint o,double ang,double scale){

    double c=scale*cos(ang), s=scale*sin(ang);

    v.x -= o.x, v.y -= o.y;

    o.x += v.x*c - v.y*s;

    o.y += v.x*s + v.y*c;

    return o;

}



int n, d;

double f, g[N];



void solve(){

    double tlen=0, res=0, ang, dx, dy, s;

    for (int i=1; i<n; i++)

        tlen += dis(cp[i],cp[i-1]);

    for (int i=0; i<n; i++)

        g[i]=res/tlen, res+=dis(cp[i],cp[i+1]);

    cpoint tmp;

    int t;

    for (int i=1; i<d; i++){

        t = 0;

        while (t<n&&dcmp(g[t]-f)<0)t++;

        if (dcmp(g[t]-f)==0){

            cp[t].put(); return;

        }

        dx = cp[t-1].x - cp[0].x;

        dy = cp[t-1].y - cp[0].y;

        tmp.x = cp[n-1].x + dx;

        tmp.y = cp[n-1].y + dy;

        ang = angle(cp[t-1],tmp,cp[t]);

        s = dis(cp[t],cp[t-1])/dis(cp[n-1],cp[0]);

        for (int j=1; j<n; j++)

            cp[j]=rotating(cp[j],cp[0],ang,s);

        for (int j=0; j<n; j++)

            cp[j].x += dx, cp[j].y += dy;

        f = (f-g[t-1])/(g[t]-g[t-1]);

    }

    t = 0;

    while (t<n&&dcmp(g[t]-f)<0)t++;

    if (dcmp(g[t]-f)==0){

        cp[t].put(); return ;

    }

    f = (f-g[t-1])/(g[t]-g[t-1]);

    dx = cp[t-1].x + (cp[t].x - cp[t-1].x) * f;

    dy = cp[t-1].y + (cp[t].y - cp[t-1].y) * f;

    printf("(%.7lf,%.7lf)\n", dx, dy);

}



int main(){

    //freopen("D:/a.txt", "r", stdin);

    int T;

    scanf("%d", &T);

    while (T--){

        scanf("%d", &n);

        for (int i=0; i<n; i++)

            cp[i].get();

        scanf("%d%lf", &d, &f);

        solve();

    }

    return 0;

}

 

复数A * B = C的几何意义是C的幅角为A和B的幅角之和,C的模为A的模和B的模的积。

有时候角度向量转换什么的比较麻烦,利用复数更容易写一些,向量V按照向量A变换向量B后的结果就是V * B / A;

View Code
#include <cstdio>

#include <cstring>

#include <cmath>

#include <algorithm>



using namespace std;



const int N = 110;

const double eps = 1e-12;



int dcmp(double x){

    return x<-eps?-1:(x>eps);

}



struct cpoint{

    double x, y;

    cpoint(){};

    cpoint(double x,double y):x(x),y(y){}

    void get() { scanf("%lf%lf", &x, &y); }

    void put() { printf("(%.7f,%.7f)\n", x, y); }

}cp[N];



struct Complex{

    double r, v;

    Complex(){}

    Complex(cpoint c){r=c.x,v=c.y;}

    Complex(double r,double v):r(r),v(v){}

    Complex operator + (const Complex& a)const{

        return Complex(r+a.r,v+a.v);

    }

    Complex operator - (const Complex& a)const{

        return Complex(r-a.r,v-a.v);

    }

    Complex operator * (const Complex& a)const{

        return Complex(r*a.r-v*a.v,v*a.r+r*a.v);

    }

    Complex operator / (const Complex& a)const{

        double R = a.r*a.r+a.v*a.v;

        return Complex((r*a.r+v*a.v)/R,(v*a.r-r*a.v)/R);

    }

};



struct cvector{

    cpoint s;

    Complex v;

    cvector(){}

    cvector(cpoint s,Complex v):s(s),v(v){}

}vec[N], tmp;



double dis(cpoint p, cpoint q){

    return sqrt((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y));

}



cpoint trans(Complex c){

    return cpoint(c.r,c.v);

}



double g[N];       //记录每段的比率



void solve(cpoint cp[], int n, int d, double f){

    int t; double len = 0, res = 0, x, y;

    for (int i=0; i<n; i++){

        vec[i]=cvector(cp[i],Complex(cp[i])-Complex(cp[0]));

        if (i) len+=dis(cp[i],cp[i-1]);

    }

    for (int i=0; i<=n; i++)

        g[i] = res / len, res += dis(cp[i],cp[i+1]);

    for (int i=1; i<d; i++){

        t = 0;

        while (t<n&&dcmp(g[t]-f)<0)t++;

        if (dcmp(g[t]-f)==0){

            vec[t].s.put(); return ;

        }

        tmp.v = vec[t].v - vec[t-1].v;

        vec[0].s = vec[t-1].s;

        for (int j=1; j<n; j++){

            vec[j].v = vec[j].v * tmp.v / vec[n-1].v;  //利用复数进行变换

            vec[j].s = trans(vec[j].v+Complex(vec[0].s));

        }

        f = (f-g[t-1])/(g[t]-g[t-1]);

    }

    t = 0;

    while (t<n&&dcmp(g[t]-f)<0)t++;

    if (dcmp(g[t]-f)==0){

        vec[t].s.put(); return ;

    }

    f = (f-g[t-1])/(g[t]-g[t-1]);

    x = vec[t-1].s.x+(vec[t].s.x-vec[t-1].s.x)*f;

    y = vec[t-1].s.y+(vec[t].s.y-vec[t-1].s.y)*f;

    cpoint(x,y).put();

}



int main(){

    //freopen("D:/a.txt", "r", stdin);

    int n, d, T;

    double f;

    scanf("%d", &T);

    while (T--){

        scanf("%d", &n);

        for (int i=0; i<n; i++)

            cp[i].get();

        scanf("%d%lf", &d, &f);

        solve(cp,n,d,f);

    }

    return 0;

}

你可能感兴趣的:(poj)