UVa 11116 Babel Towers

题目描述

Babel Inc.\texttt{Babel Inc.}Babel Inc. 设计了一种由圆形截面柱体堆叠而成的塔结构。每个柱体的高度为单位长度 111,半径为 rkr_krk,材料均匀且不可变形。柱体从底部到顶部编号为 0,1,…,n−10, 1, \dots, n-10,1,,n1,其中柱体 000 放置在地面上,柱体 kkkk≥1k \ge 1k1)放置在柱体 k−1k-1k1 的上表面上,其质心位于 (xk,yk,k+0.5)(x_k, y_k, k + 0.5)(xk,yk,k+0.5)

一个 nnn - 塔是 nnn 个柱体的堆叠。若在建造过程中(自底向上逐个添加柱体),每一步对应的子塔都是稳定的,则该塔是可行的。稳定性定义为:对于任意柱体 sss,所有堆叠在它上方的柱体(包括它自身)组成的子系统的合质心,必须严格位于柱体 s−1s-1s1 的上表面圆盘内部(边界视为不稳定)。地面可视为半径无穷大的支撑面。

给定 NNN 个柱体的设计参数,判断该塔是否可行。若不可行,输出导致倒塌的柱体编号 kkk(满足 0<k<N0 < k < N0<k<N),即添加柱体 kkk 后首次出现不稳定。

输入格式

  • 每个测试用例以整数 NNN0<N<10000 < N < 10000<N<1000)开始。
  • 接下来 NNN 行,每行三个整数 xk,yk,rkx_k, y_k, r_kxk,yk,rk,表示柱体 kkk 的质心水平坐标和半径。
  • 输入以 N=0N = 0N=0 结束。

输出格式

  • 若所有 NNN 个柱体添加后仍稳定,输出 Feasible
  • 否则,输出 Unfeasible k,其中 kkk 是第一个导致不稳定的柱体编号。

题目分析

物理模型

每个柱体的体积 Vk=πrk2⋅1V_k = \pi r_k^2 \cdot 1Vk=πrk21,由于材料均匀,质量 mk∝rk2m_k \propto r_k^2mkrk2。因此,在计算质心时,我们可以将每个柱体抽象为一个质点,位于其几何中心 (xk,yk,k+0.5)(x_k, y_k, k + 0.5)(xk,yk,k+0.5),权重为 wk=rk2w_k = r_k^2wk=rk2

对于从柱体 sss 到柱体 ttts≤ts \le tst)的子塔,其合质心的水平坐标为:

Xs,t=∑i=stwi⋅xi∑i=stwi,Ys,t=∑i=stwi⋅yi∑i=stwi X_{s,t} = \frac{\sum_{i=s}^t w_i \cdot x_i}{\sum_{i=s}^t w_i}, \quad Y_{s,t} = \frac{\sum_{i=s}^t w_i \cdot y_i}{\sum_{i=s}^t w_i} Xs,t=i=stwii=stwixi,Ys,t=i=stwii=stwiyi

该子塔放置在柱体 s−1s-1s1 的上表面上,支撑面的圆心为 (xs−1,ys−1)(x_{s-1}, y_{s-1})(xs1,ys1),半径为 rs−1r_{s-1}rs1。稳定性条件为:

(Xs,t−xs−1)2+(Ys,t−ys−1)2<rs−12 \left( X_{s,t} - x_{s-1} \right)^2 + \left( Y_{s,t} - y_{s-1} \right)^2 < r_{s-1}^2 (Xs,txs1)2+(Ys,tys1)2<rs12

判断流程

建造过程自底向上进行。设当前已添加了柱体 0,1,…,t0, 1, \dots, t0,1,,tt≥0t \ge 0t0),则对于所有可能的支撑层 s=1,2,…,ts = 1, 2, \dots, ts=1,2,,t,需要检查子塔 s…ts \dots tst 是否稳定地放置在柱体 s−1s-1s1 上。注意:

  • t=0t = 0t=0 时,只有柱体 000 放在地面上,地面视为无穷大半径,故永远稳定。
  • t≥1t \ge 1t1 时,必须检查所有 sss

一旦发现某个 sss 不满足条件,则塔在添加柱体 ttt 后倒塌,输出 ttt 即可。

复杂度分析

朴素做法:每添加一个柱体 ttt,对 sss111ttt 检查一次稳定性,每次检查需要计算 Xs,tX_{s,t}Xs,tYs,tY_{s,t}Ys,t。若直接求和,时间复杂度为 O(N3)O(N^3)O(N3),不可接受。

优化:预处理前缀和。

令:
Wi=∑p=0i−1wp,Xi=∑p=0i−1wp⋅xp,Yi=∑p=0i−1wp⋅yp W_i = \sum_{p=0}^{i-1} w_p,\quad X_i = \sum_{p=0}^{i-1} w_p \cdot x_p,\quad Y_i = \sum_{p=0}^{i-1} w_p \cdot y_p Wi=p=0i1wp,Xi=p=0i1wpxp,Yi=p=0i1wpyp

则:
∑p=stwp=Wt+1−Ws,∑p=stwpxp=Xt+1−Xs,∑p=stwpyp=Yt+1−Ys \sum_{p=s}^{t} w_p = W_{t+1} - W_s,\quad \sum_{p=s}^{t} w_p x_p = X_{t+1} - X_s,\quad \sum_{p=s}^{t} w_p y_p = Y_{t+1} - Y_s p=stwp=Wt+1Ws,p=stwpxp=Xt+1Xs,p=stwpyp=Yt+1Ys

这样每次检查可在 O(1)O(1)O(1) 时间内计算出子系统的总重量和加权坐标和。总时间复杂度为 O(N2)O(N^2)O(N2),对于 N≤1000N \le 1000N1000 完全可行。

精度处理

直接使用整数运算比较 (ΔX)2+(ΔY)2(\Delta X)^2 + (\Delta Y)^2(ΔX)2+(ΔY)2r2⋅(∑w)2r^2 \cdot (\sum w)^2r2(w)2 可能产生溢出:

  • wi=ri2≤1010w_i = r_i^2 \le 10^{10}wi=ri21010
  • 累计 Wt+1≤1000×1010=1013W_{t+1} \le 1000 \times 10^{10} = 10^{13}Wt+11000×1010=1013
  • W2≤1026W^2 \le 10^{26}W21026 远超 long long 范围(约 9×10189 \times 10^{18}9×1018

因此,必须使用高精度或浮点数比较。由于题目允许浮点误差且 NNN 不大,使用 long double 计算质心坐标并直接比较距离平方与 r2r^2r2 是安全的,边界判断时加上微小容差。

解题步骤

  1. 循环读入 NNN,若 N=0N = 0N=0 则结束。
  2. 存储所有柱体的 (xk,yk,rk)(x_k, y_k, r_k)(xk,yk,rk)
  3. 初始化前缀和数组 WWWXXXYYY,长度为 N+1N+1N+1,全部置 000
  4. 对于 t=0t = 0t=0N−1N-1N1
    • 计算 wt=rt2w_t = r_t^2wt=rt2
    • 更新前缀和:W[t+1]=W[t]+wtW[t+1] = W[t] + w_tW[t+1]=W[t]+wtX[t+1]=X[t]+wt⋅xtX[t+1] = X[t] + w_t \cdot x_tX[t+1]=X[t]+wtxtY[t+1]=Y[t]+wt⋅ytY[t+1] = Y[t] + w_t \cdot y_tY[t+1]=Y[t]+wtyt
    • t=0t = 0t=0,直接继续下一轮(地面稳定)。
    • 否则,对于 s=1s = 1s=1ttt
      • 子系统和:subW=W[t+1]−W[s]subW = W[t+1] - W[s]subW=W[t+1]W[s]subX=X[t+1]−X[s]subX = X[t+1] - X[s]subX=X[t+1]X[s]subY=Y[t+1]−Y[s]subY = Y[t+1] - Y[s]subY=Y[t+1]Y[s]
      • 计算子系统质心:cx=subX/subWcx = subX / subWcx=subX/subWcy=subY/subWcy = subY / subWcy=subY/subW
      • 计算质心到支撑面圆心的距离平方:dist2=(cx−xs−1)2+(cy−ys−1)2dist2 = (cx - x_{s-1})^2 + (cy - y_{s-1})^2dist2=(cxxs1)2+(cyys1)2
      • dist2≥rs−12−ϵdist2 \ge r_{s-1}^2 - \epsilondist2rs12ϵ,则不稳定,记录 collapseIdx=tcollapseIdx = tcollapseIdx=t 并跳出循环。
    • 若发现不稳定,跳出外层循环。
  5. 根据 feasiblefeasiblefeasible 标志输出结果。

代码实现

// Babel Towers
// UVa ID: 11116
// Verdict: Accepted
// Submission Date: 2026-04-26
// UVa Run Time: 0.000s
//
// 版权所有(C)2026,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

struct Block {
    long long x, y, r;
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int N;
    while (cin >> N, N) {
        vector<Block> blocks(N);
        for (int i = 0; i < N; ++i)
            cin >> blocks[i].x >> blocks[i].y >> blocks[i].r;
        
        vector<long long> cumW(N + 1, 0);
        vector<long long> cumX(N + 1, 0);
        vector<long long> cumY(N + 1, 0);
        
        bool feasible = true;
        int collapseIdx = -1;
        
        for (int t = 0; t < N; ++t) {
            long long w = (long long)blocks[t].r * blocks[t].r;
            cumW[t + 1] = cumW[t] + w;
            cumX[t + 1] = cumX[t] + w * blocks[t].x;
            cumY[t + 1] = cumY[t] + w * blocks[t].y;
            
            for (int s = 1; s <= t; ++s) {
                long long subW = cumW[t + 1] - cumW[s];
                long long subX = cumX[t + 1] - cumX[s];
                long long subY = cumY[t + 1] - cumY[s];
                
                // 使用 long double 避免溢出
                long double cx = (long double)subX / subW;
                long double cy = (long double)subY / subW;
                long double dx = cx - blocks[s - 1].x;
                long double dy = cy - blocks[s - 1].y;
                long double dist2 = dx * dx + dy * dy;
                
                // 边界视为不稳定,加上微小容差
                if (dist2 >= (long double)blocks[s - 1].r * blocks[s - 1].r - 1e-12) {
                    feasible = false;
                    collapseIdx = t;
                    break;
                }
            }
            if (!feasible) break;
        }
        
        if (feasible) cout << "Feasible\n";
        else cout << "Unfeasible " << collapseIdx << "\n";
    }
    
    return 0;
}

总结

本题的核心在于正确理解堆叠圆盘的稳定性物理模型,并将其转化为质心与支撑圆盘的几何约束。通过前缀和优化将 O(N3)O(N^3)O(N3) 的朴素算法降为 O(N2)O(N^2)O(N2),同时利用 long double 处理数值溢出问题。注意边界条件(圆盘边缘视为不稳定)以及浮点比较时的容差处理,即可通过在线评测。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值