Post office location problem -- divide and conquer algorithm -- Java implementation

Keywords: Java Algorithm

Problem Description:

In a city divided into regular blocks according to the east-west and North-South directions, n settlements are scattered in different blocks. The east-west direction is represented by X coordinate and the north-south direction is represented by Y coordinate. The location of each residential area can be represented by coordinates (x,y). Requirements: site selection for the post office, so as to minimize the sum of the distances from n residential areas to the post office.

Tip: weighted median (divide and conquer algorithm)

Topic analysis:

(1) n residential areas are scattered in the block, which is a two-dimensional surface, so coordinates are used to describe each residential area;

The weight here represents the importance or value of the place. For example, the weight of places with large traffic and important places such as hospitals and shopping malls should be higher;

(2) Median without weight: it is the middle value of a group of ordinal numbers. If it is odd, it is the middle number; if it is even, it is the average of the middle two numbers;

(3) Weighted median: a given number of N has a weight, or equivalent to a number, and then it is solved

How to calculate the weighted median: now sort these numbers by value, sum=    (weight of the ith number * value of the ith number itself)

If sum(k-1)=    (weight of the ith number * value of the ith number itself)    <  sum/2    

And     sum(k-1)=   (weight of the ith number * value of the ith number itself)    >=  sum/2    , Then the k-th element is the weighted median of this group

Understanding and calculation: it has been said before that the weight can actually be regarded as a number, that is, if X1=5, its weight is 3, X2=1, and its weight is 5, it should be sorted as x2 and X1 first, and then calculated according to the formula. In fact, the weight is reflected in the number to find the median: 1,1,1,1,1,5,5 to find the median of this group of numbers. Isn't the sum of the first k-1 weights above the median after expansion

(4) It is proved that the weighted median is the best solution to the one-dimensional post office location problem

From this, we can deduce two dimensions, which only need to be transformed into two one dimensions to calculate the weighted median respectively, so the calculated position is the position of the post office.

Solution process:

(1) Read data from the file (the data includes X and Y coordinates and the weights corresponding to the two coordinates)  

(2) Sort the x-axis coordinates to find the weighted median in the X direction; Sort the y-axis coordinates and find the weighted median in the Y direction (see the above for the calculation method)

(3) The coordinates composed of two weighted median are the location of the post office

The code is as follows:

(1) Entity class of residential area (originally intended to be encapsulated in consideration of practical significance, but it is found that the operation may be repeated in the later sorting, and it is more convenient to define two one-dimensional arrays)

public class Position {//Location entity class
    private double x;//Abscissa of position
    private double y;//Ordinate of position
    private double xWeight;//Weight of abscissa
    private double yWeight;//Weight of ordinate

    //Construction method
    public Position(){

    }
    //Construction method
    public Position(double x, double xWeight, double y, double yWeight) {
        this.x = x;
        this.y = y;
        this.xWeight = xWeight;
        this.yWeight = yWeight;
    }

    //get/set method
    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public double getxWeight() {
        return xWeight;
    }

    public void setxWeight(double xWeight) {
        this.xWeight = xWeight;
    }

    public double getyWeight() {
        return yWeight;
    }

    public void setyWeight(double yWeight) {
        this.yWeight = yWeight;
    }

    @Override
    public String toString() {
        return "Position{" +
                "x=" + x +
                ", y=" + y +
                ", xWeight=" + xWeight +
                ", yWeight=" + yWeight +
                '}';
    }
}

 

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Test {

    public static void main(String[] args) throws IOException {
        System.out.println("Please enter the serial number of the data to be tested:");
        Scanner input = new Scanner(System.in);
        int num = input.nextInt();
        //Read data from a file and encapsulate it
        List<Position> list = readData(".\\input_assign01_0"+num+".dat");
        System.out.println(list.toString());
        //Call the method to get the coordinates of the post office
        Position pos = postOffice(list);
        System.out.println("x:"+pos.getX()+"\ny:"+pos.getY());
    }

    /**
     * Read data
     * @param path:File path
     * @return Encapsulated residential coordinate array
     */
    public static List<Position> readData(String path) throws IOException {
        List<Position> list = new ArrayList<>();
        //Open input stream
        InputStream is = new FileInputStream(path);
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        String buffer = null;
        while ((buffer = reader.readLine())!=null){//Read by line
            String[] str = buffer.split(",");
            Position pos = new Position(Double.parseDouble(str[0]),Double.parseDouble(str[1]),Double.parseDouble(str[2]),Double.parseDouble(str[3]));
            list.add(pos);
        }
        //Close flow
        is.close();
        reader.close();
        return  list;
    }

    /**
     * Sort the coordinate set of residential areas by x or y
     * @param list Unordered set of residential coordinates
     * @param low The first position of the collection to sort
     * @param height The last position of the collection to sort
     * @param choose Determine whether to sort by x or y
     * @return Ordered coordinate set of residential areas
     */
    public static List qSort(List<Position> list, int low, int height, String choose){
        if(low>=height){//Judge the legitimacy of location
            return list;
        }
        Position temp = list.get(low);//Select a location first
        Position change = null;
        int i = low;//i pointer filters from low to high
        int j = height;//The j pointer filters from high to low
        //When sorting the weights of the x-axis
        if(choose.equals("x")){
            while(i!=j){
                while(list.get(j).getX()>=temp.getX() && i<j){j--;}//The value pointed to by J is greater than the selected value, and the j pointer moves forward
                while (list.get(i).getX()<=temp.getX() && i<j){i++;}//The value i points to is less than the selected value, and the i pointer moves back
                if(i<j) {//When the data pointed to by j is less than the data pointed to by i, the two data exchange positions put the small one in the front and the large one in the back
                    change = list.get(i);
                    list.set(i, list.get(j));
                    list.set(j, change);
                }
            }
        }
        //When sorting the weights of the y-axis, it is the same as the x-axis
        if(choose.equals("y")){
            while(i!=j){
                while(list.get(j).getY()>=temp.getY() && i<j){j--;}
                while (list.get(i).getY()<=temp.getY() && i<j){i++;}
                if(i<j){
                    change = list.get(i);
                    list.set(i,list.get(j));
                    list.set(j,change);
                }
            }
        }
        //When the small data is placed in front and the large data is placed in the back, the same location pointed by i and j is the location where the selected data should be located
        change = list.get(i);
        list.set(i,temp);
        list.set(low,change);
        //After finding the position where the first selection data should be placed, divide the data into front and back ends, and recursively sort the two sections of data in the same way
        qSort(list,low, i - 1,choose);
        qSort(list,i + 1, height,choose);
        return list;
    }

    /**
     * By sorting the x-axis and y-axis coordinates, the weighted median is calculated respectively, and the corresponding X and y are the coordinates of the post office
     * @param list: Location information of incoming settlements
     * @return
     */
    public static Position postOffice(List<Position> list){
        Position postOffice = new Position();
        double xsum = 0;//Used to record the sum of x-axis weights
        double ysum = 0;//Used to record the sum of the weights of the y-axis
        double sum = 0;
        List<Position> xlist = qSort(list,0,list.size()-1,"x");//Sort the x coordinates from small to large
//        System.out.println("x:"+xlist.toString());
        //Calculate the sum of the weights of the x-axis and y-axis respectively
        for(int i=0;i<list.size();i++){
            xsum+=list.get(i).getxWeight();
            ysum+=list.get(i).getyWeight();
        }
        //Find the weighted median of the x-axis as the abscissa of the post office
        for(int j=0;j<xlist.size();j++){
            sum+=xlist.get(j).getxWeight();
            if(sum > xsum/2){//When the sum of accumulated weights is just greater than half of the sum of weights, the corresponding x value is the weighted median
                postOffice.setX(xlist.get(j).getX());
                break;
            }
        }
        //Sort the y coordinates from small to large
        List<Position> ylist = qSort(list,0,list.size()-1,"y");
//        System.out.println("y:"+ylist.toString());
        sum = 0;
        //Find the weighted median of the y-axis as the ordinate of the post office
        for(int k=0;k<ylist.size();k++){
            sum+=ylist.get(k).getyWeight();
            if(sum > ysum/2){
                postOffice.setY(ylist.get(k).getY());
                break;
            }
        }
        return postOffice;
    }
}

  Enter data storage format:

They represent x coordinate, x weight, y coordinate and Y weight respectively. Each row represents a settlement  

 

Posted by gravedig2 on Sat, 16 Oct 2021 01:26:09 -0700