POJ2677.Tour

试题请参见: http://poj.org/problem?id=2677

题目概述

John Doe, a skilled pilot, enjoys traveling. While on vacation, he rents a small plane and starts visiting beautiful places. To save money, John must determine the shortest closed tour that connects his destinations. Each destination is represented by a point in the plane pi = < xi,yi >. John uses the following strategy: he starts from the leftmost point, then he goes strictly left to right to the rightmost point, and then he goes strictly right back to the starting point. It is known that the points have distinct x-coordinates.

Write a program that, given a set of n points in the plane, computes the shortest closed tour that connects the points according to John’s strategy.

解题思路

对所有点按照横坐标排序.

假设从点Pi到点Pj的路线是从Pi出发, 从右至左至P1, 再从左至右至Pj. 并且保证Pi和Pmax(i, j)中的每个点恰好经过一次. 我们定义d(i, j)为Pi到点Pj的最短路径. 由于对称性, 我们只考虑i≥j的情况. 另外, 我们将Pi和Pj间的距离记作∆(i, j).

我们需要计算d(n, n). 很显然Pn到Pn的最短路径可能是从P1至Pn, P2至Pn, …, Pn-1至Pn. 则:
d(n,n)=min{d(n,1)+∆(n,1),d(n,2)+∆(n,2),…,d(n,n-1)+∆(n,n-1)}

对于计算d(i,j), 并且i≥j. 初始条件为d(2, 1)= ∆(2, 1).

  • 若j<i-1, 那么 d(i,j)=d(i-1,j)+∆(i,i-1)
  • 若j=i-1, 那么 d(i,i-1)=min{d(1,i-1)+∆(1,i),d(2,i-1)+∆(2,i),…,d(i-2,i-1)+∆(i-2,i)}.

根据对称性d(i,j) = d(j, i).

源代码

import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    private class Point implements Comparable<Point> {
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public int compareTo(Point p) {
            return this.x - p.x;
        }

        public int x;
        public int y;
    }

    public double getMinDistance(Point[] points) {
        int n = points.length;
        if ( n == 1 ) {
            return 0;
        }
        double[][] delta = new double[n][n];
        double[][] d = new double[n][n];

        Arrays.sort(points);
        for ( int i = 0; i < n; ++ i ) {
            for ( int j = 0; j < i; ++ j ) {
                delta[i][j] = getDistance(points[i], points[j]);
                delta[j][i] = delta[i][j];
            }
        }
        for ( int i = 0; i < n; ++ i ) {
            d[i][0] = delta[i][0];
        }
        for( int i = 1; i < n - 1; ++ i ) {
            d[i + 1][i] = Integer.MAX_VALUE;
            for( int j = 0; j < i; ++ j ) {
                d[i + 1][j] = d[i][j] + delta[i][i + 1];
                d[i + 1][i] = Math.min(d[i + 1][i], d[i][j] + delta[i + 1][j]);
            }
        }
        return d[n - 1][n - 2] + delta[n - 1][n - 2];
    }

    private double getDistance(Point a, Point b) {
        return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }

    public static void main(String[] args) {
        Main s = new Main();

        Scanner in = new Scanner(System.in);
        while ( in.hasNext() ) {
            int n = in.nextInt();
            Point[] points = new Point[n];

            for ( int i = 0; i < n; ++ i ) {
                int x = in.nextInt();
                int y = in.nextInt();
                points[i] = s.new Point(x, y);
            }
            DecimalFormat df = new DecimalFormat("0.00"); 
            System.out.println(df.format(s.getMinDistance(points)));
        }
        in.close();
    }
}

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值