双调欧几里得旅行商问题-《算法导论》

题目描述
给定平面上n个点作为输入,要求从最左端的点开始,严格向右前进,直到最右端的点,再严格向左前进到第一个点,每一个点只能经过一次。
主算法:
d(i,j) 表示两个人第一个点出发沿着不同的路径分别走到 i,j 并且经过 1max(i,j) 的所有点到达终点还需要的距离。 dist(i,j) 表示 i,j 的欧几里得距离。
因此, d(i,j)=d(j,i) ,不妨设 i>j ,一步一步“蚕食”所有的点,则下一步的决策无非是,第一个人走到 i+1 ,或者第二个人走到 i+1 个点,所以

d(i,j)=min(d(i+1,j)+dist(i,i+1),d(i+1,i)+dist(j,i+1))

边界情况

d(n1,j)=dist(n1,n)+dist(j,n)

所以

ans=d(2,1)+dist(2,1)
给出主代码

double dp(int i,int j)
{
    double &ans = d[i][j];
    if(ans>0)return ans;
    else{
        if(i==n-1)
        {
            ans = dist(j,n)+dist(n-1,n);
        }else
        {
            ans =  min(dp(i+1,i)+dist(i+1,j),dp(i+1,j)+dist(i,i+1));
        }
        return ans;
    }
}

题目链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4093
ac代码

#include
#include
#include
#include
#define maxn 1009
#include
using namespace std;

double d[maxn][maxn];
int c[maxn][2];
int n;
double dist(int i,int j)
{
 int dx = c[i][0] -c[j][0];
 int dy = c[i][1] - c[j][1];
 return hypot(dx,dy);
}

double dp(int i,int j)
{
    double &ans = d[i][j];
    if(ans>0)return ans;
    else{
        if(i==n-1)
        {
            ans = dist(j,n)+dist(n-1,n);
        }else
        {
            ans =  min(dp(i+1,i)+dist(i+1,j),dp(i+1,j)+dist(i,i+1));
        }
        return ans;
    }
}




int main()
{
    //freopen("H:\\c++\\file\\stdin.txt","r",stdin);

    while(scanf("%d",&n) !=EOF)
    {
        memset(d,-1,sizeof(d));
        for(int i=1; i<=n ; ++i)scanf("%d %d",&c[i][0],&c[i][1]);
        printf("%.2lf\n",dp(2,1)+dist(2,1));
    }

    return 0;
 } 

你可能感兴趣的:(算法理论)