UVa 11116 Babel Towers

AI5天前发布 beixibaobao
6 0 0

题目描述


Babel
 
Inc.
texttt{Babel Inc.}
Babel Inc.
设计了一种由圆形截面柱体堆叠而成的塔结构。每个柱体的高度为单位长度
1
1
1
,半径为
r
k
r_k
rk
,材料均匀且不可变形。柱体从底部到顶部编号为
,
1
,

,
n

1
0, 1, dots, n-1
0,1,,n1
,其中柱体 0 放置在地面上,柱体
k
k
k

k

1
k ge 1
k1
)放置在柱体
k

1
k-1
k1
的上表面上,其质心位于
(
x
k
,
y
k
,
k
+
0.5
)
(x_k, y_k, k + 0.5)
(xk,yk,k+0.5)

一个
n
n
n
– 塔是
n
n
n
个柱体的堆叠。若在建造过程中(自底向上逐个添加柱体),每一步对应的子塔都是稳定的,则该塔是可行的。稳定性定义为:对于任意柱体
s
s
s
,所有堆叠在它上方的柱体(包括它自身)组成的子系统的合质心,必须严格位于柱体
s

1
s-1
s1
的上表面圆盘内部(边界视为不稳定)。地面可视为半径无穷大的支撑面。

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

输入格式

  • 每个测试用例以整数
    N
    N
    N

    <
    N
    <
    1000
    0 < N < 1000
    0<N<1000
    )开始。
  • 接下来
    N
    N
    N
    行,每行三个整数
    x
    k
    ,
    y
    k
    ,
    r
    k
    x_k, y_k, r_k
    xk,yk,rk
    ,表示柱体
    k
    k
    k
    的质心水平坐标和半径。
  • 输入以
    N
    =
    N = 0
    N=0
    结束。

输出格式

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

题目分析

物理模型

每个柱体的体积
V
k
=
π
r
k
2

1
V_k = pi r_k^2 cdot 1
Vk=πrk21
,由于材料均匀,质量
m
k

r
k
2
m_k propto r_k^2
mkrk2
。因此,在计算质心时,我们可以将每个柱体抽象为一个质点,位于其几何中心
(
x
k
,
y
k
,
k
+
0.5
)
(x_k, y_k, k + 0.5)
(xk,yk,k+0.5)
,权重为
w
k
=
r
k
2
w_k = r_k^2
wk=rk2

对于从柱体
s
s
s
到柱体
t
t
t

s

t
s le t
st
)的子塔,其合质心的水平坐标为:


X
s
,
t
=

i
=
s
t
w
i

x
i

i
=
s
t
w
i
,
Y
s
,
t
=

i
=
s
t
w
i

y
i

i
=
s
t
w
i
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

1
s-1
s1
的上表面上,支撑面的圆心为
(
x
s

1
,
y
s

1
)
(x_{s-1}, y_{s-1})
(xs1,ys1)
,半径为
r
s

1
r_{s-1}
rs1
。稳定性条件为:


(
X
s
,
t

x
s

1
)
2
+
(
Y
s
,
t

y
s

1
)
2
<
r
s

1
2
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

判断流程

建造过程自底向上进行。设当前已添加了柱体
,
1
,

,
t
0, 1, dots, t
0,1,,t

t

t ge 0
t0
),则对于所有可能的支撑层
s
=
1
,
2
,

,
t
s = 1, 2, dots, t
s=1,2,,t
,需要检查子塔
s

t
s dots t
st
是否稳定地放置在柱体
s

1
s-1
s1
上。注意:


  • t
    =
    t = 0
    t=0
    时,只有柱体 0 放在地面上,地面视为无穷大半径,故永远稳定。

  • t

    1
    t ge 1
    t1
    时,必须检查所有
    s
    s
    s

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

复杂度分析

朴素做法:每添加一个柱体
t
t
t
,对
s
s
s

1
1
1

t
t
t
检查一次稳定性,每次检查需要计算
X
s
,
t
X_{s,t}
Xs,t

Y
s
,
t
Y_{s,t}
Ys,t
。若直接求和,时间复杂度为
O
(
N
3
)
O(N^3)
O(N3)
,不可接受。

优化:预处理前缀和。

令:

W
i
=

p
=
i

1
w
p
,
X
i
=

p
=
i

1
w
p

x
p
,
Y
i
=

p
=
i

1
w
p

y
p
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
=
s
t
w
p
=
W
t
+
1

W
s
,

p
=
s
t
w
p
x
p
=
X
t
+
1

X
s
,

p
=
s
t
w
p
y
p
=
Y
t
+
1

Y
s
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
(
N
2
)
O(N^2)
O(N2)
,对于
N

1000
N le 1000
N1000
完全可行。

精度处理

直接使用整数运算比较
(
Δ
X
)
2
+
(
Δ
Y
)
2
(Delta X)^2 + (Delta Y)^2
(ΔX)2+(ΔY)2

r
2

(

w
)
2
r^2 cdot (sum w)^2
r2(w)2
可能产生溢出:


  • w
    i
    =
    r
    i
    2

    10
    10
    w_i = r_i^2 le 10^{10}
    wi=ri21010
  • 累计
    W
    t
    +
    1

    1000
    ×
    10
    10
    =
    10
    13
    W_{t+1} le 1000 times 10^{10} = 10^{13}
    Wt+11000×1010=1013

  • W
    2

    10
    26
    W^2 le 10^{26}
    W21026
    远超 long long 范围(约
    9
    ×
    10
    18
    9 times 10^{18}
    9×1018

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

解题步骤

  1. 循环读入
    N
    N
    N
    ,若
    N
    =
    N = 0
    N=0
    则结束。
  2. 存储所有柱体的
    (
    x
    k
    ,
    y
    k
    ,
    r
    k
    )
    (x_k, y_k, r_k)
    (xk,yk,rk)
  3. 初始化前缀和数组
    W
    W
    W

    X
    X
    X

    Y
    Y
    Y
    ,长度为
    N
    +
    1
    N+1
    N+1
    ,全部置 0
  4. 对于
    t
    =
    t = 0
    t=0

    N

    1
    N-1
    N1

    • 计算
      w
      t
      =
      r
      t
      2
      w_t = r_t^2
      wt=rt2
    • 更新前缀和:
      W
      [
      t
      +
      1
      ]
      =
      W
      [
      t
      ]
      +
      w
      t
      W[t+1] = W[t] + w_t
      W[t+1]=W[t]+wt

      X
      [
      t
      +
      1
      ]
      =
      X
      [
      t
      ]
      +
      w
      t

      x
      t
      X[t+1] = X[t] + w_t cdot x_t
      X[t+1]=X[t]+wtxt

      Y
      [
      t
      +
      1
      ]
      =
      Y
      [
      t
      ]
      +
      w
      t

      y
      t
      Y[t+1] = Y[t] + w_t cdot y_t
      Y[t+1]=Y[t]+wtyt

    • t
      =
      t = 0
      t=0
      ,直接继续下一轮(地面稳定)。
    • 否则,对于
      s
      =
      1
      s = 1
      s=1

      t
      t
      t

      • 子系统和:
        s
        u
        b
        W
        =
        W
        [
        t
        +
        1
        ]

        W
        [
        s
        ]
        subW = W[t+1] – W[s]
        subW=W[t+1]W[s]

        s
        u
        b
        X
        =
        X
        [
        t
        +
        1
        ]

        X
        [
        s
        ]
        subX = X[t+1] – X[s]
        subX=X[t+1]X[s]

        s
        u
        b
        Y
        =
        Y
        [
        t
        +
        1
        ]

        Y
        [
        s
        ]
        subY = Y[t+1] – Y[s]
        subY=Y[t+1]Y[s]
      • 计算子系统质心:
        c
        x
        =
        s
        u
        b
        X
        /
        s
        u
        b
        W
        cx = subX / subW
        cx=subX/subW

        c
        y
        =
        s
        u
        b
        Y
        /
        s
        u
        b
        W
        cy = subY / subW
        cy=subY/subW
      • 计算质心到支撑面圆心的距离平方:
        d
        i
        s
        t
        2
        =
        (
        c
        x

        x
        s

        1
        )
        2
        +
        (
        c
        y

        y
        s

        1
        )
        2
        dist2 = (cx – x_{s-1})^2 + (cy – y_{s-1})^2
        dist2=(cxxs1)2+(cyys1)2

      • d
        i
        s
        t
        2

        r
        s

        1
        2

        ϵ
        dist2 ge r_{s-1}^2 – epsilon
        dist2rs12ϵ
        ,则不稳定,记录
        c
        o
        l
        l
        a
        p
        s
        e
        I
        d
        x
        =
        t
        collapseIdx = t
        collapseIdx=t
        并跳出循环。
    • 若发现不稳定,跳出外层循环。
  5. 根据
    f
    e
    a
    s
    i
    b
    l
    e
    feasible
    feasible
    标志输出结果。

代码实现

// 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 << "Feasiblen";
        else cout << "Unfeasible " << collapseIdx << "n";
    }
    return 0;
}

总结

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

© 版权声明

相关文章