0
点赞
收藏
分享

微信扫一扫

洛谷P1523 旅行商简化版【DP】【绿】

微笑沉默 2022-03-27 阅读 27

Date:2022.03.26
题目背景
欧几里德旅行商(Euclidean Traveling Salesman)问题也就是货郎担问题一直是困扰全世界数学家、计算机学家的著名问题。现有的算法都没有办法在确定型机器上在多项式时间内求出最优解,但是有办法在多项式时间内求出一个较优解。
为了简化问题,而且保证能在多项式时间内求出最优解,J.L.Bentley提出了一种叫做bitonic tour的哈密尔顿环游。它的要求是任意两点(a,b)之间的相互到达的代价dist(a,b)=dist(b,a)且任意两点之间可以相互到达,并且环游的路线只能是从最西端单向到最东端,再单项返回最西端,并且是一个哈密尔顿回路。
题目描述
著名的NPC难题的简化版本
现在笛卡尔平面上有n(n<=1000)个点,每个点的坐标为(x,y)(-231<x,y<231,且为整数),任意两点之间相互到达的代价为这两点的欧几里德距离,现要你编程求出最短bitonic tour。
输入格式
第一行一个整数n
接下来n行,每行两个整数x,y,表示某个点的坐标。
输入中保证没有重复的两点,
保证最西端和最东端都只有一个点。
输出格式
一行,即最短回路的长度,保留2位小数。
输入输出样例
输入 #1复制
7
0 6
1 0
2 3
5 4
6 1
7 5
8 2
输出 #1复制
25.58

思路:题意就是从起点到终点和从终点到起点的路径组成一个哈密顿回路,即:除了起点和终点外无额外交点。转化模型,从起点走出两条路径到终点,途中两条路径无交叉点(即走不到同一个点)的最短路径和。我们将所有点按横坐标排序,题意保证最左最右两点唯一。
由此,状态方程: f [ i ] [ j ] : f[i][j]: f[i][j]:一条路径走到 i i i号点、另一条路径走到 j j j号点的最短距离。
初始状态: f [ 1 ] [ 1 ] = 0 ; f[1][1]=0; f[1][1]=0;
状态转移:
首先,我们要知道 i 、 j i、j ij哪个才是靠后的,因为要考虑最后一个点也就是 k = m a x ( i , j ) + 1 k=max(i,j)+1 k=max(i,j)+1要接在 i i i还是 j j j后面。
f [ i ] [ k ] = f [ i ] [ j ] + g [ j ] [ k ] ; f[i][k]=f[i][j]+g[j][k]; f[i][k]=f[i][j]+g[j][k];【接在j后面】
f [ k ] [ j ] = f [ i ] [ j ] + g [ i ] [ k ] ; f[k][j]=f[i][j]+g[i][k]; f[k][j]=f[i][j]+g[i][k];【接在i后面】
注意,其实无需考虑图中是否有 i = = j i==j i==j的情况,根本不可能。若 i = = j i==j i==j k k k显然能让这两者不相等。但是注意,最后如果我们要保证答案在 f [ n ] [ n ] f[n][n] f[n][n],当 k = = n + 1 k==n+1 k==n+1时也就代表有一条路径到 n n n号点了,因此另一条就直接到 n n n号点即可。
答案: f [ n ] [ n ] ; f[n][n]; f[n][n];

代码如下:

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PII;
const LL N = 1010,INF=0x3f3f3f3f3f3f3f3f;
typedef long long LL;
LL t,n,m,a[N],miny=1e18,maxy=-1e18,l,r;
double dist[N],g[N][N],f[N][N];
struct node 
{
    LL x,y,idx;
}s[N];
bool st[N];
bool cmp(node a,node b) {return a.x<b.x;}
double dis(LL x1,LL y1,LL x2,LL y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            if(i==j) g[i][j]=0;
            else g[i][j]=1000000000000000000.0;
            f[i][j]=1000000000000000000.0;
        }
    for(int i=1;i<=n;i++) cin>>s[i].x>>s[i].y;
    sort(s+1,s+1+n,cmp);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            g[i][j]=g[j][i]=dis(s[i].x,s[i].y,s[j].x,s[j].y);
    f[1][1]=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            //if(i!=j||i==1)
            {
                LL k=max(i,j)+1;
                if(k==n+1)
                {
                    if(j==n) f[n][n]=min(f[n][n],f[i][n]+g[i][n]);
                    if(i==n) f[n][n]=min(f[n][n],f[n][j]+g[n][j]);
                }
                else
                {
                    f[k][j]=min(f[k][j],f[i][j]+g[i][k]);
                    f[i][k]=min(f[i][k],f[i][j]+g[j][k]);
                }
            }
        }
    printf("%.2lf",f[n][n]);
    return 0;
}
举报

相关推荐

0 条评论