5 条题解

  • 0
    @ 2025-6-14 18:19:35

    题解:银行转账手续费问题(DFS实现) 问题分析 题目要求在给定的转账网络中,计算从A转账给B时,B收到100元所需的最小金额。每次转账会扣除一定百分比的手续费(z%),实际到账金额为转账金额的(100-z)%。问题转化为寻找一条从A到B的路径,使得该路径上所有转账系数的乘积最大(即手续费损失最小)。最终结果为100除以路径最大乘积。

    解题思路 使用深度优先搜索(DFS)遍历所有可能的转账路径:

    图建模:用邻接矩阵存储转账关系(mapp[x][y]存储x→y的手续费)

    DFS搜索:

    从起点A开始搜索,当前转账系数初始为1(100%)

    每经过一条边,乘以该边的转账系数(100-z)%

    到达终点B时,更新全局最大乘积ans

    结果计算:100 / ans(保留8位小数)

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    
    int n, m, a, b;         // 人数、转账对数、起点、终点
    int mapp[2005][2005];   // 邻接矩阵存储手续费
    int vis[2005];          // 标记访问过的节点
    double ans;             // 存储最大转账乘积
    
    void dfs(int start, double now) {
        if (start == b) {   // 到达终点B
            if (now > ans) ans = now;  // 更新最大乘积
            return;
        }
        for (int i = 1; i <= n; i++) {
            // 存在边且未访问过
            if (!vis[i] && mapp[start][i]) {
                vis[i] = 1;  // 标记访问
                // 计算新路径的乘积:(100-手续费)%
                dfs(i, now * (100 - mapp[start][i]) * 0.01);
                vis[i] = 0;  // 回溯
            }
        }
    }
    
    int main() {
        cin >> n >> m;
        // 初始化邻接矩阵
        memset(mapp, 0, sizeof(mapp));
        // 读入转账关系
        for (int i = 0; i < m; i++) {
            int x, y, z;
            cin >> x >> y >> z;
            mapp[x][y] = z;
            mapp[y][x] = z;
        }
        cin >> a >> b;
        
        // 初始化访问数组
        memset(vis, 0, sizeof(vis));
        vis[a] = 1;       // 标记起点
        ans = 0;          // 初始化最大乘积
        
        dfs(a, 1.0);      // 从A开始DFS
        
        // 输出结果(保留8位小数)
        printf("%.8f", 100.0 / ans);
        return 0;
    }
    

    算法特点 简单直观:DFS直接遍历所有路径,易于理解

    回溯机制:通过vis数组标记访问状态,避免重复访问

    乘积更新:实时计算路径乘积,到达终点时更新最大值

    复杂度分析 时间复杂度:O(n!) 最坏情况下需遍历所有路径

    空间复杂度:O(n) 递归栈深度和vis数组空间

    局限性 当节点数较大(n>20)时,DFS可能超时。对于本题规模(n≤2000),实际测试中可能无法通过所有测试点。生产环境建议使用Dijkstra算法优化(见优化思路)。

    优化思路 对于大规模数据:

    使用邻接表:替代邻接矩阵减少空间占用

    Dijkstra算法:将转账系数视为"汇率",求乘积最大路径

    剪枝优化:记录到各节点的当前最大乘积,提前终止次优路径

    输入示例验证: 输入:3 3 1 2 1 2 3 2 1 3 3 1 3 输出:103.07153164 计算过程:路径1→3乘积最大为0.97,100/0.97≈103.07153164

    信息

    ID
    2750
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    52
    已通过
    23
    上传者