最短路径【DP】

题目大意:

求一个无向图的欧拉回路中最短路,要求去时和回时各经过一个特殊点。
InoutInout

5 1 3
1 3
3 4
4 1
7 5
8 3

OutputOutput

18.18

思路:

欧拉回路?最短路?费用流?不,是DPDP
要是没有两个特殊点的存在,这道题就是一个裸的欧拉回路。
但是有了这两个点,就是DPDP了。
当我们从点11到达点n时,要从点nn回点1时,可以发现,这是一个无向图,从点nn到点1的路径就是从点11到点n的路径!
那么这道题就转化为:求两条从点11到点n的边,要求这两条路径互不干涉,每一条路径经过一个特殊点,且要求路径长度之和最短。
f[i][j]f[i][j]为第一条路径到达点ii,第二条路径到达点j的最短路径和,那么就有

k=max(i,j)+1k=max(i,j)+1
f[k][j]=min(f[k][j],f[i][j]+dis[i][k])f[k][j]=min(f[k][j],f[i][j]+dis[i][k])
f[i][k]=min(f[i][k],f[i][j]+dis[j][k])f[i][k]=min(f[i][k],f[i][j]+dis[j][k])

最终任意一条路径到达终点时
f[n][n]=min(f[n][n],f[i][j]+dis[i][n])f[n][n]=min(f[n][n],f[i][j]+dis[i][n])
f[n][n]=min(f[n][n],f[i][j]+dis[j][n])f[n][n]=min(f[n][n],f[i][j]+dis[j][n])

代码:

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;

double f[1011][1011],x[1011],y[1011],dis[1011][1011];
int n,b1,b2,k;

int main()
{
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
    scanf("%d%d%d",&n,&b1,&b2);
    for (int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&x[i],&y[i]);
        for (int j=1;j<i;j++)
         dis[i][j]=dis[j][i]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));  //求直线距离
    }
    for (int i=0;i<=n;i++)
     for (int j=0;j<=n;j++)
      f[i][j]=2147483647;  //初始化
    f[1][1]=0;
    for (int i=1;i<=n;i++)
     for (int j=1;j<=n;j++)
     { 
        if (i==j&&i>1) continue;  //判断
        k=max(i,j)+1; 
        if (k>n)  //到达终点
        {
            if (i<n) f[n][n]=min(f[n][n],f[i][j]+dis[i][n]);
            if (j<n) f[n][n]=min(f[n][n],f[i][j]+dis[j][n]);
        }
        else   //没到达终点
        {
            if (k!=b2+1) f[k][j]=min(f[k][j],f[i][j]+dis[i][k]);
            if (k!=b1+1) f[i][k]=min(f[i][k],f[i][j]+dis[j][k]);
        }
     } 
    printf("%0.2lf\n",f[n][n]);
    return 0;
}
### 使用动态规划解决最短路径问题 #### DP表的构造与应用 当使用动态规划来解决问题时,构建DP表是一个至关重要的环节。对于最短路径问题而言,无论是单源还是多源的情况,都可以通过设计合理的状态转移方程以及初始化边界条件来进行有效求解。 在处理像网格这样的结构化环境下的最短路径问题时,可以创建一个二维数组`dp[i][j]`表示到达位置(i,j)处所需的最小代价[^4]。此方法适用于从起点至终点存在唯一方向约束的情形,比如仅允许向右或向下走动;而对于更复杂场景,则需调整策略以适应不同类型的输入数据特性。 具体来说,在填充表格的过程中遵循自底向上原则——即先计算规模较小的子问题再逐步扩展到更大范围内的解决方案直至覆盖整个待求区域。这不仅有助于简化逻辑推理过程而且能够显著提高程序运行效率[^1]。 考虑到一个多维空间内任意两点间距离度量的需求,如图论中提到的多源最短路径案例[Floyd-Warshall算法](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm),同样可以通过建立类似的矩阵形式记录每一对节点间的最佳连接情况,并迭代更新这些值直到收敛于最终结果[^2]。 下面给出一段Python代码片段用于展示基于上述思路实现的具体操作: ```python def minPathSum(grid): if not grid or not grid[0]: return 0 rows, cols = len(grid), len(grid[0]) dp = [[float('inf')] * cols for _ in range(rows)] dp[0][0] = grid[0][0] for i in range(1, rows): dp[i][0] = dp[i - 1][0] + grid[i][0] for j in range(1, cols): dp[0][j] = dp[0][j - 1] + grid[0][j] for i in range(1, rows): for j in range(1, cols): dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] return dp[-1][-1] ``` 这段代码实现了在一个m×n大小的地图上寻找由左上方出发抵达右下方所经过路线累积权重最低的方法。它首先设置了初始状态,接着按照既定规则逐层推进完成全部格点数值设定最后返回目标坐标的累计开销作为答案输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值