1. 程式人生 > >計蒜客Bounty-Hunter多路dp

計蒜客Bounty-Hunter多路dp

題意:

Spike is a bounty hunter and he is currently tracking a criminal! To investigate he uses his spaceship, the Swordfish II, and travels to Ndifferent places on 2D Euclidean space before returning to his crew at the starting location with all the information he has gathered. The starting location is the leftmost place (with the lowest x-coordinate) and Spike wants to travel to everyeveryother place before returning. However space fuel costs a lot of Woolongs and Spike would rather spend his money on special beef with bell peppers. Therefore he wants to travel the minimum possible distance.

On top of that he is being chased by the Red Dragon crime syndicate. To make sure they don’t catch him he can only visit places in increasing order of their xx-coordinate until he reaches the rightmost place (with the largest x-coordinate), then he can turn around and visit places in decreasing order of their x-coordinate until he reaches his starting location again.

Input

The input starts with an integer T(1≤T≤100) specifying the number of test cases that follow.

Each test case consists of an integer N(2≤N≤512) specifying the number of places in the tour.

The coordinates of these places are given as integers in the next NN lines, xx-coordinate first, yy-coordinate second (0≤x,y≤5000).

The places are given in ascending order of the x-coordinate.

Every place has a unique x-coordinate.

Output

For each test case, output on a single line the minimum travel distance needed to complete the tour.

Your output should have an absolute or relative error of at most 10^-2

樣例輸入

2
5
0 1
1 2
2 0
3 2
4 1
3
100 1
200 1
300 1

樣例輸出

9.300563079746
400

大概意思就是給T組樣例,每組樣例有n個地方,從最左邊開始,從左往右走到最右邊,再從最右邊返回到最左邊,每個點有且經過一次,求最短路徑

思路:

​ 我們找一個人從起點開始繞一圈的最短路,其實就是找兩個人從起點到達終點(兩個人除了終點和起點,不能經過相同的點)路徑和的最小值。這是一個旅行商問題。由於505數值太大,因此可以用多路dp來求解

​ 我們設dp【i】【j】保證第一個人到達i點,第二個人到達j點,i < j且j之前的所有點都經過的最小花費,有關遞推式在程式碼中有標註

程式碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define inf 0x3f3f3f3f
using namespace std;

struct node {
    double x, y;
}point[550];

bool zfq (node A, node B) {
    return A.x < B.x;
}

double sq(node A, node B) {
    return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}

double dp[550][550];      //dp[i][j]保證第一個到達i點,第二個人到達j點,i < j且j之前的所有點都經過的最小花費
double d[550][550];

int main() {
    int T, n;
    scanf("%d", &T);
    while (T--) {
        double ans = inf;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%lf%lf", &point[i].x, &point[i].y);
        }
        sort(point, point + n, zfq);
        for (int i = 0; i < n; i ++) {
            for (int j = i + 1; j < n; j++) {
                dp[i][j] = inf;
                d[i][j] = sq(point[i], point[j]);
            }
        }
        dp[0][1] = d[0][1];
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                dp[j][j + 1] = min (dp[j][j + 1], dp[i][j] + d[i][j + 1]);//可能是i走到j+1
                dp[i][j + 1] = min (dp[i][j + 1], dp[i][j] + d[j][j + 1]);//也可能是j走到j+1
            }
        }
        for (int i = 0; i < n - 1; i ++) {
            ans = min(ans, dp[i][n - 1] + d[i][n - 1]);	//由於i<j,所以需額外加一個for迴圈求dp[n-1][n-1]的最小值
        }
        printf("%f\n", ans);
    }
    return 0;
}

如果有寫的不對或者不全面的地方 可通過主頁的聯絡方式進行指正,謝謝