HDU2224 TSP(货郎担)问题DP

来源:互联网 发布:本子画师推荐 知乎 编辑:程序博客网 时间:2024/06/07 05:45

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2224

很经典的TSP一类问题了:给出平面上的N个点(1~N),让你从 1 号点出发走到最右端的点 N ,再返回 1 ,要求中途不能重复走某个点而且必须把所有点全走一遍,求最小的总路径。

我们大致可以这样想:把折返问题拆分成两次从 1 到 N 的路径当然还得满足题目要求(中途不能重复走某个点而且必须把所有点全走一遍)。这样我们设状态量dp[ i ][ j ]来表示从 1 到 i 以及从 1 到 j 的最小总路径(满足题目要求),并且设定i < j,因为显然dp[ j ][ j ]=dp[ j -- 1 ][ j ]+dis[ j-1 ][ j ](两点间距离),那么转移方程我们可以想到:①当 i < j - 1时,dp[ i ][ j ]=dp[ i ][ j - 1 ]+dis[ j - 1 ][ j ]很显然由于i < j-1 ,dp[ i ][ j ]只能来源于dp[ i ][ j - 1 ]。②当i = j - 1 时,dp[ j - 1 ][ j ]就可以来源于dp[ k ][ j -1 ] + dis[ k ][ j ](k < j - 1)。

#include "iostream"#include "cstdio"#include "cstring"#include "algorithm"#include "cmath"using namespace std;int N;struct NODE{    double x,y;}p[205];double dis[205][205],dp[205][205];void solve(){    int i,j,k;    dp[1][2]=dis[1][2];    for(j=3;j<=N;j++)    {        for(i=1;i<j-1;i++)        {            dp[i][j]=dp[i][j-1]+dis[j-1][j];        }        dp[j-1][j]=999999999;        for(i=1;i<j-1;i++)        {            dp[j-1][j]=min(dp[j-1][j],dp[i][j-1]+dis[i][j]);        }    }    dp[N][N]=dp[N-1][N]+dis[N-1][N];}int main(){    while(~scanf("%d",&N))    {        int i,j,k;        for(i=1;i<=N;i++) scanf("%lf %lf",&p[i].x,&p[i].y);        for(i=1;i<=N;i++) for(j=i+1;j<=N;j++) dis[i][j]=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));        solve();        printf("%.2lf\n",dp[N][N]);    }}

 

0 0