[动态规划] UVa1347 旅行 (DAG的固定起点终点的最短路)

题目

这里写图片描述

思路

1.抽象(神乎其技):由于从左到右不方便思考,可以将问题转换为,两个人同时从最左点出发,沿着两条路径走,最后都走到最右点,并且除了起点和终点外每个点恰好被一个人走过。
2.状态定义:(i,j),表示1~i已经全部走过,且两个人分别位于i,j(i>j)。
3.指标函数:d(i,j),还需要走的距离。
4.状态转移方程:

d ( i , j ) = m i n ( d ( i + 1 , j ) + d i s [ i ] [ i + 1 ] , d ( i + 1 , i ) + d i s t [ j ] [ i + 1 ] )



本题的难点,在于推理出合适的状态定义:
这里写图片描述

代码

由于double不能批量赋值为-1,所以本代码采用了vis数组,空间换易读性。

#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int INF = 1 << 30;
const int maxn = 1000 + 100;
int n;
double d[maxn][maxn], dist[maxn][maxn], vis[maxn][maxn];
struct Point {
    int x, y;
}A[maxn];

double dp(int i, int j) {
    double &ans = d[i][j];
    if (vis[i][j]) return ans;
    double d1 = dp(i + 1, j) + dist[i][i + 1];
    double d2 = dp(i + 1, i) + dist[j][i + 1];
    ans = min(d1, d2);
    vis[i][j] = 1;
    return ans;
}

int main() {
    while (scanf("%d", &n) == 1) {
        _rep(i, 1, n) scanf("%d%d", &A[i].x, &A[i].y);
        _rep(i, 1, n)
            _rep(j, 1, n)
            dist[i][j] = dist[j][i] = sqrt(pow(A[i].x - A[j].x, 2) + pow(A[i].y - A[j].y, 2));

        //memset(d, -1.0, sizeof(d));  // double不可以批量赋值-1
        memset(vis, 0, sizeof(vis));
        d[n][n - 1] = 0.0; vis[n][n - 1] = 1;
        _rep(i, 1, n - 2) {
            d[n][i] = 1.0 * INF;
            vis[n][i] = 1;
        }
        double ans = dp(1, 1);
        printf("%.2lf\n", ans+dist[n-1][n]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80740811
今日推荐