POJ-2677 Tour(双调欧几里得旅行商问题)(动态规划)

经典动态规划问题:双调欧几里得旅行商问题


题意:给定平面n个点作为输入,希望你可以从最左端走到最右端,
然后再返回到最左端,就是一个回路。要求经过所有点的最短回路


j < i - 1时,d[i][j] = d[i-1][j] + dis(i-1,i)
j = i-1时,d[i][j] = d[i][i-1] = min(d[i][i-1],d[k][j]+dis(i,k))
dp[n][n]=dp[n-1][n]+dist(n-1,n)

参考自here

/*
经典动态规划问题:双调欧几里得旅行商问题
题意:给定平面n个点作为输入,希望你可以从最左端走到最右端,
然后再返回到最左端,就是一个回路。要求经过所有点的最短回路
j < i - 1时,d[i][j] = d[i-1][j] + dis(i-1,i)
j = i-1时,d[i][j] = d[i][i-1] = min(d[i][i-1],d[k][j]+dis(i,k))
dp[n][n]=dp[n-1][n]+dist(n-1,n)
*/
#include
#include
#include
#include
using namespace std;

const int N = 1005;
const double INF = 0x3f3f3f3f*1.0;
struct point
{
    double x,y;
}p[N];
double d[N][N];//从i到最左端,再到j的最短路径
double dist(int i,int j)
{
    return 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));
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(d,0,sizeof(d));
        for(int i = 1;i <= n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);

        //计算所有情况下的b[i][j]
        d[1][2] = dist(1,2);
        for(int i = 3;i <= n;i++)
        {
            //j < i - 1时,d[i][j] = d[i-1][j] + dis(i-1,i)
            for(int j = 1;j <= i-2;j++)
                d[j][i] = d[j][i-1] + dist(i-1,i);

            //j = i-1时,d[i][j] = d[i][i-1] = min(d[i][i-1],d[k][j]+dis(i,k))
            d[i-1][i] = INF;
            for(int j = 1;j <= i-2;j++)
            {
                if(d[j][i-1] + dist(j,i) < d[i-1][i])
                    d[i-1][i] = d[j][i-1] + dist(j,i);
            }
        }
        d[n][n] = d[n-1][n] + dist(n-1,n);
        printf("%.2f\n",d[n][n]);
    }
    return 0;
}


你可能感兴趣的:(动态规划)