博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[poj][3845][Fractal]

Posted on 2012-07-21 22:18  紫华弦筝  阅读(219)  评论(0编辑  收藏  举报

题目: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;
}