hdu 2224 The shortest path

3 篇文章 0 订阅

本题归结为旅行推销员问题(Travelling Salesman Problem, 又称为旅行商问题、货郎担问题、TSP问题)是一个多局部最优的最优化问题:有n个城市,一个推销员要从其中某一个城市出发,唯一走遍所有的城市,再回到他出发的城市,求最短的路线。

研究NP问题时看到了计算欧式平面最短哈密顿回路的贪心算法, 只能得到近似解

此算法在本题上得到了应用

具体求解步骤为将计算简化为求出最短双调TSP回路, 将所有点按x坐标排序后, 先从最左端点向右走按递增顺序达到最右端点然后再按递减顺序走回, 因为期间没有折返, 所以可以保证x方向局部最优.

由于题目给出的点已经按x坐标排序, 所以可以省去排序这一步

这种贪心算法的优势在于时间效率, 如果要得到最优解, 需要枚举每两个点, 算法复杂度将达到O(n!). 如果利用动态规划则可以达到O(n^2 2^n) 但仍然太慢

利用双调TSP回路计算, 在应用动归时算法复杂度只有O(n^{2})


对于其他的TSP求解方法可以参见:

http://episte.math.ntu.edu.tw/articles/mm/mm_11_3_02/index.html

具体算法图示可见http://en.wikipedia.org/wiki/Travelling_salesman_problem



/*author: birdstorm*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <climits>

#define MAXN 205
#define N 105
#define inf 1.0e20
#define eps 1.0e-10
#define MOD 1000000007

#define For(i,m,n) for(int i=(m);i<(n);i++)
#define vecfor(iter,a) for(vector<int>::iterator iter=a.begin();iter!=a.end();iter++)
#define rep(i,m,n) for(int i=(m);i<=(n);i++)
#define LL long long

using namespace std;
pair<int,int> p[MAXN];
double dp[MAXN][MAXN], dist[MAXN][MAXN];

double dis(int x, int y)
{
    double t1=p[x].first-p[y].first;
    double t2=p[x].second-p[y].second;
    return sqrt(t1*t1+t2*t2);
}
int main()
{
    int n;
    while(~scanf("%d",&n)){
        double ans=inf;
        rep(i,1,n) scanf("%d%d",&p[i].first,&p[i].second);
        rep(i,2,n) rep(j,1,i-1) dist[i][j]=dis(i,j);
        dp[2][1]=dist[2][1];
        rep(i,3,n){
            rep(j,1,i-2) dp[i][j]=dp[i-1][j]+dist[i][i-1];
            dp[i][i-1]=inf;
            rep(j,1,i-2) dp[i][i-1]=min(dp[i-1][j]+dist[i][j],dp[i][i-1]);
            if(i==n) dp[i][i]=dp[i][i-1]+dist[i][i-1];
        }
        printf("%.2lf\n",dp[n][n]);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值