LoginSignup
0
1

More than 5 years have passed since last update.

paizaキャンペーン問題「怪盗813からの挑戦状」を解いてみた

Last updated at Posted at 2017-09-02

問題を解いたら、抽選でAmazonギフト券とかお肉とかが貰えるとのことで、チャレンジしてみた。
https://paiza.jp/poh/phantom_thief

問題

お宝の場所の情報は怪盗の居る場所を 0, 0 として N 個 のお宝の x, y 座標がメートル単位で書かれています。
各座標間は直線で移動します。0, 0 の位置からスタートし、可能な限り短いルートでお宝を全て盗むルートを出力してください。

考え方

原点から一番近い座標を出力して、その座標からまた一番近い座標を出力して…を繰り返せば、短いルートで進めるのでは?と思って、解いてみた。

解答をブログとかに書いてもいいと書いてあったので、以下に掲載。

提出コード
import java.util.*;

public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String firstLine = sc.nextLine().replaceAll(" ","");
        int itemCount = Integer.parseInt(firstLine);

        ArrayList<Point> pointList = new ArrayList<Point>();

        //標準入力から座標リストを作成する
        for(int i = 0; i < itemCount ; i++){
            String[] line = sc.nextLine().split(" ");
            int x = Integer.parseInt(line[0]);
            int y = Integer.parseInt(line[1]);
            pointList.add(new Point(x,y));
        }

        Point originPoint = new Point(0,0);
        while(pointList.size() > 0){
            int minDistance = Integer.MAX_VALUE;
            Point minDistancePoint = new Point();

            //基準点から一番距離の近い座標を座標リストから取得する
            for(Point getPoint : pointList){
                int tmpDistance = getDistance(originPoint,getPoint);
                if(minDistance > tmpDistance){
                    minDistance = tmpDistance;
                    minDistancePoint = getPoint;
                }
            }
            //座標位置を表示する
            minDistancePoint.output();
            //基準点を変更する
            originPoint = minDistancePoint;
            //座標リストから座標を削除する
            int index = pointList.indexOf(minDistancePoint);
            pointList.remove(index);
        }
    }

    //二点の座標間の距離を求める
    public static int getDistance(Point p1, Point p2) {
            double x1 = p1.x;
            double y1 = p1.y;
            double x2 = p2.x;
            double y2 = p2.y;

        double distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
        return (int) distance;
    }

}

//座標クラス
class Point{
    int x;
    int y;

    public Point(){
        this.x = 0;
        this.y = 0;
    }

    public Point(int x , int y){
        this.x = x;
        this.y = y;
    }

    public void output(){
        System.out.println(x + " " + y);
    }
}

結果

こちら。最適解じゃなかったようだ。
https://paiza.jp/poh/phantom_thief/result/a8a222d8

最適解を求めるには?

ちょっと調べたところ、巡回セールスマン問題と呼ばれる問題っぽい。
(最初の座標に戻らなくていいので、少し違う?)

今回私が解いた方法は「欲張り法」というアルゴリズムのようだ。

巡回セールスマン問題を解くためのアルゴリズムには「2-opt法」「山登り法」「焼きなまし法」などがあり、これらを使うともっと最適解に近くなるようだけど、難しそうなので諦めた。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1