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;
}
相关推荐
Estella-Ealine9 天前
5.10 周赛vp 2026 ICPC Gran Premio de Mexico 1ra Fecha E题
icpc·2026
所以遗憾是什么呢?10 天前
【题解】Codeforces Round 1097 (Div. 2, Based on Zhili Cup 2026) (致理杯) ABCDEF
数据结构·算法·acm·codeforces·icpc·ccpc·xcpc
漂流瓶jz17 天前
UVA-1152 和为0的4个值 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·二分查找·题解·aoapc·算法竞赛入门经典·uva
AKDreamer_HeXY18 天前
QOJ 12255 - 36 Puzzle 题解
数据结构·c++·数学·算法·icpc·qoj
漂流瓶jz1 个月前
UVA-120 煎饼 题解答案代码 算法竞赛入门经典第二版
数据结构·c++·算法·排序·aoapc·算法竞赛入门经典·uva
所以遗憾是什么呢?1 个月前
【题解】Codeforces Round 1081 (Div. 2)
数据结构·c++·算法·acm·icpc·ccpc·xcpc
漂流瓶jz1 个月前
UVA-10384 推门游戏 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·深度优先·题解·aoapc·算法竞赛入门经典·uva
漂流瓶jz2 个月前
UVA-11846 找座位 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·排序算法·深度优先·aoapc·算法竞赛入门经典·uva
老鼠只爱大米2 个月前
LeetCode经典算法面试题 #70:爬楼梯(朴素递归、记忆化递归、动态规划等六种实现方案详解)
算法·leetcode·动态规划·递归·斐波那契·矩阵快速幂·爬楼梯
闻缺陷则喜何志丹2 个月前
【计算几何】和差化积及积化和差
c++·数学·计算几何