POJ1579.Function Run Fun

本文介绍了一个三参数递归函数的实现与优化方法。通过使用动态规划避免重复计算,显著提高了运行效率。文章提供了完整的源代码及调试过程。

试题请参见: http://poj.org/problem?id=1579

题目概述

We all love recursion! Don’t we?

Consider a three-parameter recursive function w(a, b, c):

if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns:
1

if a > 20 or b > 20 or c > 20, then w(a, b, c) returns:
w(20, 20, 20)

if a < b and b < c, then w(a, b, c) returns:
w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)

otherwise it returns:
w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)

This is an easy function to implement. The problem is, if implemented directly, for moderate values of a, b and c (for example, a = 15, b = 15, c = 15), the program takes hours to run because of the massive recursion.

解题思路

非常简单的递推, 并且已经给出了状态转移方程.

我们要做的就是Copy it. 但是有一个问题, 我们需要记录每一次计算的结果, 以免重复计算造成TLE.

遇到的问题

我写错了判断条件你敢信!!
(请注意是a <= 0而不是a < 0).

源代码

#include <iostream>

const int MAX_SIZE = 21;
int table[MAX_SIZE][MAX_SIZE][MAX_SIZE] = {0};

int w(int a, int b, int c) {
    if ( a <= 0 || b <= 0 || c <= 0 ) {
        return 1;
    } else if ( a > 20 || b > 20 || c > 20 ) {
        return w(20, 20, 20);
    }

    if ( table[a][b][c] == 0 ) {
        if ( a < b && b < c ) {
            table[a][b][c] = w(a, b, c - 1) + w(a, b - 1, c - 1) - w(a, b - 1, c);
        } else {
            table[a][b][c] = w(a - 1, b, c) + w(a - 1, b - 1, c) + w(a - 1, b, c - 1) - w(a - 1, b - 1, c - 1);
        }
    }
    return table[a][b][c];
}

int main() {
    int a = 0, b = 0, c = 0;

    while ( std::cin >> a >> b >> c ) {
        if ( a == -1 && b == -1 && c == -1 ) {
            break;
        }
        std::cout << "w(" << a << ", " << b << ", " << c << ")"
                  << " = " << w(a, b, c) << std::endl;
    }
    return 0;
}
<think>好的,我现在要解决用户关于POJ1986 Distance Queries的问题。首先,我需要确认这个题目的具体内容和要求。用户可能是在准备算法竞赛或者学习数据结构,需要了解这个问题的解决方法。 POJ1986的题目名称是Distance Queries,应该属于最近公共祖先(LCA)或树上的路径查询问题。这类问题通常需要预处理树结构,以便快速回答两点之间的距离。用户可能需要知道如何高效处理多次查询。 接下来,我需要回忆或查找POJ1986的具体描述。根据经验,这类问题通常是给定一棵无向树,多次询问两点之间的最短距离。因为树中任意两点路径唯一,所以距离可以通过LCA来计算。距离公式一般是dist(u, v) = dist(root, u) + dist(root, v) - 2 * dist(root, lca(u, v))。 接下来,我需要考虑如何实现。通常有两种方法:Tarjan的离线算法和倍增法的在线算法。Tarjan算法在处理所有查询时效率很高,但需要提前知道所有查询点。而倍增法则允许在线处理,每次查询的时间复杂度是O(log n),适合处理大量随机查询。 然后,思考具体步骤。首先,构建树的邻接表,记录每个节点的子节点和边的权值。接着,预处理每个节点的深度和到根节点的距离。对于倍增法,还需要预处理每个节点向上2^k步的祖先节点。这一步通常通过DFS或BFS完成。 预处理完成后,对于每个查询(u, v),找到它们的LCA,然后利用之前计算的到根节点的距离来计算两点间的路径长度。这一步需要确保LCA查找的正确性,否则计算结果会出错。 可能需要注意的细节包括树的根节点选择(通常选1号节点),以及处理输入数据时可能有无关的边方向信息,但题目可能给出的是无向树,因此邻接表需要双向添加,但遍历时要记录父节点避免回溯。 另外,输入数据中可能有冗余信息,比如题目中的“路”和“方向”,但实际可以忽略方向,因为树是无向的。需要提醒用户注意处理输入时只需提取有效信息。 测试样例的处理也很重要,例如当u和v相同时,距离应为0;当其中一个是另一个的祖先时,计算是否准确。需要确保代码能处理这些边界情况。 最后,总结解决方法,给出算法步骤和复杂度分析。时间复杂度主要是预处理O(n log n)和每次查询O(log n),空间复杂度O(n log n)用于存储倍增表。这样的复杂度对于n到4e4和查询数到1e4的情况应该是可以接受的。 用户可能需要具体的代码实现,但根据要求,不需要提供代码,而是解释思路。所以应该分步骤说明解决过程,确保用户理解如何应用LCA和距离计算的方法。 可能遇到的常见错误包括忘记处理双向边导致死循环,或者预处理时没有正确计算每个节点的深度和距离。需要提醒用户注意这些点。 总结来说,回答应该包括问题分析、解决方法(LCA的应用)、算法步骤、复杂度说明以及可能的注意事项,帮助用户全面理解如何解决POJ1986的问题。</think>### POJ1986 Distance Queries 问题详解 #### 问题背景 题目要求计算树结构中多个节点对之间的最短路径长度。给定一棵包含 $N$ 个节点(节点编号从 $1$ 开始)的无向树,每条边带有权值。需回答 $M$ 次查询,每次给出两个节点 $u$ 和 $v$,输出它们之间的最短距离。 #### 核心思路:LCA + 前缀和 1. **树的性质**:树中任意两节点间有唯一路径,最短距离即路径边权之和。 2. **LCA(最近公共祖先)**:路径必经两节点的最近公共祖先。设 $dist[u]$ 表示根节点到 $u$ 的路径长度,则两点间距离公式为: $$dist(u, v) = dist[u] + dist[v] - 2 \cdot dist[LCA(u, v)]$$ 3. **倍增法求LCA**:通过预处理每个节点向上跳 $2^k$ 步的祖先,实现 $O(\log n)$ 时间复杂度的查询。 --- #### 解决步骤 **1. 树的存储与预处理** - **邻接表存树**:记录每个节点的相邻节点及边权。 - **DFS/BFS预处理**: - 计算每个节点的深度 $depth[u]$ 和到根节点距离 $dist[u]$。 - 构建倍增表 $up[u][k]$,表示节点 $u$ 向上跳 $2^k$ 步的祖先。 **2. LCA查询实现** - **调整深度对齐**:将较深节点上跳至与另一节点同深度。 - **同步上跳找LCA**:从最大步长开始尝试,若祖先不同则上跳,直至找到共同祖先。 **3. 距离计算** - 根据公式直接计算,无需实际遍历路径。 --- #### 复杂度分析 - **预处理**:DFS/BFS遍历 $O(N)$,倍增表构建 $O(N \log N)$。 - **单次查询**:$O(\log N)$。 - **总复杂度**:$O(N \log N + M \log N)$,适用于 $N \leq 4 \times 10^4$ 和 $M \leq 10^4$ 的规模。 --- #### 关键实现细节 1. **根节点选择**:通常选择 $1$ 号节点为根,需保证树连通。 2. **输入处理**:忽略无关的方向信息,按无向边构建邻接表。 3. **倍增表初始化**: - $up[u][0]$ 直接父节点。 - 递推公式:$up[u][k] = up[ up[u][k-1] ][k-1]$。 4. **边界条件**: - 查询的两个节点相同时,距离为 $0$。 - 节点为对方祖先时需正确触发上跳终止条件。 --- #### 示例说明 **输入**: ``` 7 6 1 6 13 E 6 3 9 E 3 5 7 S 4 1 3 N 2 4 20 W 4 7 2 S 3 1 6 1 4 2 6 ``` **处理过程**: 1. 建树后,根为 $1$,计算各节点 $dist$ 值。 2. 查询 $2$ 和 $6$: - LCA(2,6) 为 $4$。 - 距离 = $dist[2] + dist[6] - 2 \cdot dist[4] = 3 + 13 - 2 \cdot 3 = 16$。 --- #### 总结 POJ1986 是经典的LCA应用问题,通过结合倍增法和前缀和,能够高效处理树上的路径查询。需注意树的存储、预处理细节及边界条件,代码实现时可选择DFS或BFS进行初始化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值