当前位置:首页 > 蓝桥杯 > 【2020蓝桥杯国赛C组】补给题解析:从Floyd到动态规划的高效解法

【2020蓝桥杯国赛C组】补给题解析:从Floyd到动态规划的高效解法

2天前

【2020蓝桥杯国赛C组】补给题解析:从Floyd到动态规划的高效解法 蓝桥杯国赛 Floyd算法 动态规划 最短路径优化 第1张

一、题目解读

2020年蓝桥杯国赛C组“补给”题目要求:给定n个村庄坐标及最大补给距离D,需判断是否所有村庄均可从总部(村庄0)直接或间接到达,并计算访问所有村庄的最小路径(即旅行商问题TSP)。题目核心在于构建模型,处理最短路径与路径规划问题,考察图论算法动态规划的应用。

二、解题思路

1. 问题分析:首先将村庄坐标转化为图论中的节点,边权为欧几里得距离。若两点距离≤D,则边存在,否则视为不可达。

2. 最短路径计算:采用Floyd-Warshall算法计算任意两点间的最短路径,构建完整距离矩阵。

3. 路径规划优化:转化为TSP问题,使用动态规划求解。状态定义为已访问村庄的集合(二进制掩码)与当前位置,通过状态转移方程逐步扩展路径。

4. 可行性判断:若总部与任一村庄不可达,直接输出-1;否则计算最小路径。

三、解题步骤

1. 输入与初始化:读取村庄数量n和最大距离D,存储村庄坐标到vector<pair<int, int>>。

2. 构建邻接矩阵:计算所有村庄间的欧几里得距离,若距离≤D则赋值,否则设为INF(表示不可达)。

3. Floyd-Warshall算法:三层循环更新任意两点间的最短路径,利用传递性优化距离。

4. 动态规划求解TSP:

    状态定义:dp[mask][i]表示已访问村庄集合为mask,当前位于村庄i的最小路径。

    边界条件:dp[1][0] = 0(仅访问总部)。

    状态转移:枚举当前村庄last和下一村庄next,若next在mask中且路径可达,更新dp[mask | (1 << next)][next] = min(dp[mask][last] + dist[last][next])。

5. 输出结果:检查所有村庄是否可达,并返回最小路径或-1。

四、代码与注释

#include <iostream>
#include <vector>
#include <cmath>
#include <iomanip>
#include <algorithm>
using namespace std;

const double INF = 1e18;

// 计算两点之间的欧几里得距离
double calculateDistance(int x1, int y1, int x2, int y2) {
    return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}

int main() {
    int n, D;
    cin >> n >> D;
    
    vector<pair<int, int>> villages(n); // 存储村庄坐标
    for (int i = 0; i < n; ++i) {
        cin >> villages[i].first >> villages[i].second;
    }
    
    // 构建邻接矩阵,计算所有村庄之间的距离
    vector<vector<double>> dist(n, vector<double>(n, INF));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            double d = calculateDistance(villages[i].first, villages[i].second, 
                                       villages[j].first, villages[j].second);
            // 如果距离超过D,则不能直接到达
            dist[i][j] = (d <= D)? d : INF;
        }
    }
    
    // Floyd-Warshall算法计算所有点对之间的最短路径
    for (int k = 0; k < n; ++k) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
    
    // 检查是否所有村庄都可到达
    for (int i = 1; i < n; ++i) {
        if (dist[0][i] == INF || dist[i][0] == INF) {
            cout << "-1" << endl;
            return 0;
        }
    }
    
    // 旅行商问题(TSP)的动态规划解法
    vector<vector<double>> dp(1 << n, vector<double>(n, INF));
    dp[1][0] = 0; // 初始状态:只访问了总部(村庄0)
    
    for (int mask = 1; mask < (1 << n); ++mask) {
        for (int last = 0; last < n; ++last) {
            if (!(mask & (1 << last))) continue;
            if (dp[mask][last] == INF) continue;
            
            for (int next = 0; next < n; ++next) {
                if (mask & (1 << next)) {
                    dp[mask | (1 << next)][next] = 
                        min(dp[mask | (1 << next)][next], dp[mask][last] + dist[last][next]);
                }
            }
        }
    }
    
    // 输出最小路径
    cout << fixed << setprecision(2) << dp[(1 << n) - 1][0] << endl;
    return 0;
}

五、总结

1. 算法选择:Floyd-Warshall适用于稠密图的最短路径计算,动态规划有效解决TSP的路径规划问题,二者结合能高效处理题目要求。

2. 时间复杂度:Floyd为O(n^3),动态规划为O(2^n * n^2),在n较小(如题目限制)时可行。

3. 优化方向:若村庄数量较大,可尝试启发式算法(如分支限界)或近似算法降低复杂度。

4. 解题启示:将实际问题转化为经典算法模型(图论+动态规划)是竞赛解题的核心能力,需熟练掌握算法适用场景与实现细节。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣70题:告别暴力递归!从零实现记忆化搜索解法

力扣70题:告别暴力递归!从零实现记忆化搜索解法

题意解析:想象你站在楼梯底部,面前有n级台阶。每次你可以选择跨1级或2级台阶,最终到达顶端的路径有多少种不同的走法?这个问题本质上是在探索分叉决策的叠加效果——当我们把每个台阶处的选择看作二叉树的分支...

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

一、题目解读题目要求在一个n×m的网格中,从左上角到右下角选择一条路径,路径上的数字可重复取用,求取数之和的最大值。路径限制为仅能向右或向下移动。需注意路径的灵活性与重复取数的可能性,传统单向动态规划...

牛客12576题解题全解析:动态规划+质因数分解实现跳跃问题最优解

牛客12576题解题全解析:动态规划+质因数分解实现跳跃问题最优解

一、题目解读牛客12576题是一道经典的算法题,要求给定起点N和终点M,求解从N到M的最少跳跃次数。题目考察的核心在于路径优化与动态规划思想,需结合数论中的质因数分解技巧,通过合理设计算法降低时间复杂...

LeetCode 120题三角形最小路径和最优解法:动态规划详解与代码实现

LeetCode 120题三角形最小路径和最优解法:动态规划详解与代码实现

一、题目解读LeetCode 120题“三角形最小路径和”要求给定一个由数字组成的三角形,从顶部开始向下移动,每次可向左或向右移动一格,计算从顶至底的最小路径和。三角形以二维向量形式给出,每层元素数量...

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

一、题目解读洛谷P4551题要求在一个无向图中,寻找任意两点路径权值异或后的最大值。题目输入为图的边信息(点数n和n-1条边),每条边包含起点、终点及权值。需输出所有路径中权值异或的最大值。问题核心在...

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

一、题目解读    1999年NOIP提高组“导弹拦截”问题(对应洛谷P1020)要求设计导弹拦截系统:给定一组导弹高度数据,需计算最少拦截系统数量,并求最多能...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。