UVa1497/LA5719 A Letter to Programmers

UVa1497/LA5719 A Letter to Programmers

题目链接

  本题是2011年icpc亚洲区预赛北京赛区G

题意

  空间里有 n(n≤1 000)个点,你的任务是执行一段程序,输出程序运行结束后所有点的坐标。一共有 5 条指令,如下表所示。

指令 说 明
translate tx ty tz 所有点(x,y,z)移动到(x+tx,y+ty,z+tz)
scale a b c 所有点(x,y,z)移动到(ax,by,cz)
rotate a b c d 所有点旋转。旋转轴是(0,0,0)-(a,b,c),旋转角度是d 度。如果你站在(a,b,c)并且面朝(0,0,0),旋转呈逆时针
repeat k 和 end 配对,二者之间的指令重复执行k 次。k 为32 位带符号整数。注意 repeat 和 end 之间可以嵌套 repeat。
end 和 repeat 指令配对或者作为程序终止

  程序不超过100 行,除了n 和k 之外所有参数的绝对值均不超过1 000。

分析

  按题意构造平移、缩放、旋转三种变换矩阵(可以参考三维仿射变换矩阵),将所有变换矩阵乘起来得到最终的变换矩阵,然后对每个输入点计算出答案即可。注意处理 repeat 需要用矩阵快速幂计算加速。

一个坑点

  题目说输出坐标的结果四舍五入到小数点第二位,我用 io manipulator 来控制小数点,但由于运算过程中三角函数等带来的精度损失,坐标值都加上 1e-6 才 AC 的。

AC 代码

cpp 复制代码
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

int n, t; const double e = M_PI/180.; char s[10]; double a[4][4], p[4][4], c[4][4], r[52][4][4];

void identity_mat(double (&t)[4][4]) {
    for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) t[i][j] = i==j ? 1. : 0.;
}

void trans_mat(double tx, double ty, double tz, double (&t)[4][4]) {
    identity_mat(t); t[0][3] = tx; t[1][3] = ty; t[2][3] = tz;
}

void scale_mat(double a, double b, double c, double (&t)[4][4]) {
    identity_mat(t); t[0][0] = a; t[1][1] = b; t[2][2] = c;
}

void rot_mat(double a, double b, double c, double d, double (&t)[4][4]) {
    double s = sqrt(a*a + b*b + c*c); a /= s; b /= s; c /= s; d *= e;
    double co = cos(d), si = sin(d), c1 = 1.-co; identity_mat(t);
    t[0][0] = co + a*a*c1; t[0][1] = a*b*c1 - c*si; t[0][2] = a*c*c1 + b*si;
    t[1][0] = a*b*c1 + c*si; t[1][1] = co + b*b*c1; t[1][2] = b*c*c1 - a*si;
    t[2][0] = a*c*c1 - b*si; t[2][1] = b*c*c1 + a*si; t[2][2] = co + c*c*c1;
}

void copy(const double (&a)[4][4], double (&b)[4][4]) {
    for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) b[i][j] = a[i][j];
}

void mat_mul(const double (&a)[4][4], const double (&b)[4][4], double (&c)[4][4]) {
    for (int i=0; i<4; ++i) for (int j=0; j<4; ++j) {
        c[i][j] = 0.;
        for (int k=0; k<4; ++k) c[i][j] += a[i][k]*b[k][j];
    }
}

void mat_pow(const double (&x)[4][4], int y, double (&b)[4][4]) {
    identity_mat(b); copy(x, p);
    while (y) {
        if (y & 1) mat_mul(b, p, a), copy(a, b);
        if (y >>= 1) mat_mul(p, p, a), copy(a, p);
    }
}

void dfs(int k = -1) {
    while (true) {
        cin >> s;
        if (s[0] == 'r' && s[1] == 'e') {
            int k1; cin >> k1; identity_mat(r[++t]); dfs(k1);
        } else if (s[0] == 'e') {
            if (k >= 0) mat_pow(r[t], k, c), mat_mul(c, r[--t], a), copy(a, r[t]);
            return;
        } else {
            if (s[0] == 't') {
                double x, y, z; cin >> x >> y >> z; trans_mat(x, y, z, c);
            } else if (s[0] == 's') {
                double x, y, z; cin >> x >> y >> z; scale_mat(x, y, z, c);
            } else {
                double x, y, z, d; cin >> x >> y >> z >> d; rot_mat(x, y, z, d, c);
            }
            mat_mul(c, r[t], a); copy(a, r[t]);
        }
    }
}

void solve() {
    identity_mat(r[t=0]); dfs();
    while (n--) {
        double x, y, z; cin >> x >> y >> z;
        cout << r[0][0][0]*x + r[0][0][1]*y + r[0][0][2]*z + r[0][0][3] + 1e-6 << ' ' << 
            r[0][1][0]*x + r[0][1][1]*y + r[0][1][2]*z + r[0][1][3] + 1e-6 << ' ' << 
            r[0][2][0]*x + r[0][2][1]*y + r[0][2][2]*z + r[0][2][3] + 1e-6 << endl;
    }
    cout << endl;
}

int main() {
    cout << fixed << setprecision(2);
    while (cin >> n && n) solve();
    return 0;
}
相关推荐
惆怅客1234 天前
UVa12327/LA5705 Xavier is Learning to Count
fft·快速傅里叶变换·容斥原理·icpc·uva·生成函数的乘法
闻缺陷则喜何志丹8 天前
【几何】指定半径倒角的实现,暂不考虑误差
数学·计算几何·几何·倒角
惆怅客12314 天前
UVa1507/LA5838 Shadow
计算几何·icpc·坐标变换·uva·二维凸包·离散化扫描法·圆和凸多边形的面积并
Estella-Ealine1 个月前
5.10 周赛vp 2026 ICPC Gran Premio de Mexico 1ra Fecha E题
icpc·2026
所以遗憾是什么呢?1 个月前
【题解】Codeforces Round 1097 (Div. 2, Based on Zhili Cup 2026) (致理杯) ABCDEF
数据结构·算法·acm·codeforces·icpc·ccpc·xcpc
漂流瓶jz1 个月前
UVA-1152 和为0的4个值 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·二分查找·题解·aoapc·算法竞赛入门经典·uva
AKDreamer_HeXY1 个月前
QOJ 12255 - 36 Puzzle 题解
数据结构·c++·数学·算法·icpc·qoj
漂流瓶jz2 个月前
UVA-120 煎饼 题解答案代码 算法竞赛入门经典第二版
数据结构·c++·算法·排序·aoapc·算法竞赛入门经典·uva
所以遗憾是什么呢?2 个月前
【题解】Codeforces Round 1081 (Div. 2)
数据结构·c++·算法·acm·icpc·ccpc·xcpc
漂流瓶jz2 个月前
UVA-10384 推门游戏 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·深度优先·题解·aoapc·算法竞赛入门经典·uva