• 动态规划双调欧几里得旅行商问题 linux


    发现自己实在是太弱了,这个算法理解的太慢了...

    具体的解法参照别人的解题思路,我自己动手重新编了代码,加深自己的学习印象。

    双调欧几里得旅行商问题

       欧几里得旅行商问题是对平面上给定的n个点确定一条连接各点的最短闭合旅程的问题。如图(a)给出了一个7个点问题的解。这个问题的一般形式是NP完全的,故其解需要多于多项式的时间。

        J.L. Bentley 建议通过只考虑双调旅程(bitonic tour)来简化问题,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。下图(b)显示了同样的7个点的最短双调路线。在这种情况下,多项式的算法是可能的。事实上,存在确定的最优双调路线的O(n*n)时间的算法。

       

        注:在一个单位栅格上显示的平面上的七个点。 a)最短闭合路线,长度大约是24.89。这个路线不是双调的。b)相同点的集合上的最短双调闭合路线。长度大约是25.58。

    解:

    算法的基本思想:

    首先将给出的点排序,关键字x,重新编号,从左至右1,2,3,…,n。

        定义p[i][j],表示结点i到结点j之间的距离。(图b)

        定义d[i][j],表示从i连到1,再从1连到j,(注意,i>j,且并没有相连。)(图a)

      

        对于任意一个点i来说,有两种连接方法,一种是如图(a)所示,i与i-1相连,另一种呢是如图(b),i与i-1不相连。

        根据双调旅程,我们知道结点n一定与n相连,那么,如果我们求的d[n][n-1],只需将其加上p[n-1][n]就是最短双调闭合路线。

    根据上图,很容易写出方程式:

    d[i][j]=d[i-1][j]+p[i][i-1];     

      d[i][i-1]=min(d[i-1][j]+p[j][i]);

    算法的代码:

    #include<iostream>

    #include<cmath>

    #include<stdio.h>

    using namespace std;

    const int maxn=101;

    struct{

    int x,y;

    }a[maxn];

    double d[maxn][maxn],p[maxn][maxn];

    int n;

    double min(double x,double y)

    {

           if(x>y)

                  return y;

           else

                  return x;

    }

    void init()

    {

           int i;

           scanf("%d",&n);

           for(i=1;i<=n;i++)

           {//输入我们要游经的点的坐标

                  scanf("%d%d",&a[i].x,&a[i].y);

           }

           for(i=1;i<=n;i++)

           {

                  printf("a[%d].x=%d,a[%d].y=%d\n",i,a[i].x,i,a[i].y);

           }

    }

    void qsort(int l,int r)

    {//这里是快速排序,将所有的输入点按照X坐标排序

                  int i=l,j=r,mid=a[(i+j)>>1].x;

                  while(i<j)

                  {

                                while(a[i].x<mid)i++;

                                while(mid<a[j].x)j--;

                                if(i<=j)

                                {

                                       swap(a[i].x,a[j].x);

                                       swap(a[i].y,a[j].y);

                                       i++;j--;

                                }

                  }

                  for(int m=1;m<=r;m++)

                  {

                         printf("a[%d].x=%d,a[%d].y=%d\n",m,a[m].x,m,a[m].y);

                  }

                  if(l<j)

                         qsort(l,j);

                  if(i<r)

                         qsort(i,r);

    }

    double cnt(int x1,int y1,int x2,int y2)

    {//具体计算两个点之间距离的算法

           int x=(x1-x2)*(x1-x2);

           int y=(y1-y2)*(y1-y2);

           return sqrt(x+y);   

    }

    void work_p()

    {//将所有的两两点之间的距离计算出来,因为此处是对称矩阵所以只需要计算一半

           int i,j;

           for(i=1;i<n;i++)

                  for(j=i+1;j<=n;j++)

                         {

                                p[i][j]=p[j][i]=cnt(a[i].x,a[i].y,a[j].x,a[j].y);

                         }

    }

    void DP()

    {     //这里是动态规划思想的主要体现部分

           int i,j;

        d[1][1]=0;

        for (i=2;i<=n;i++)

            d[i][1]=p[i][1];

           //

        for (i=2;i<n;i++)

        {

            d[i+1][i]=INT_MAX;

            for (j=1;j<=i-1;j++)

            {

                d[i+1][j]=d[i][j]+p[i][i+1];//不是相邻点的时候计算比较简单,(j,i+1处于两条边上)

                d[i+1][i]=min(d[i+1][i],d[i][j]+p[j][i+1]); //是相邻点的时候就要计算最小值出来(从哪里断开,能够使得i到i+1的距离最小)

            }

        }

    }

    int main()

    {

        freopen("data.in","r",stdin);

        freopen("data.out","w",stdout);

        init();

        qsort(1,n);

        work_p();

        DP();

        printf("result is %.2lf\n",d[n][n-1]+p[n][n-1]);

           fclose(stdin);

        fclose(stdout);

        return 0;

    }

  • 相关阅读:
    .Net中World转PDF
    asp.net开启多线程异步处理
    win8.1 安装kb2999226 一直提示 搜索更新
    MVC实例应用模式
    MVC模式
    23种设计模式
    Android 的Android Device Monitor 打不开出现 A error has occured
    xxx系统的可用性和易用性分析
    淘宝网的质量属性分析
    《架构漫谈》读后感
  • 原文地址:https://www.cnblogs.com/lgz24/p/1758691.html
Copyright © 2020-2023  润新知