算法第一次作业-邮局选址问题

一、运行环境:

Win7、MyEclipse、JDK8

二、运行过程说明:

数据文件格式:第一行是居民数量n的取值,第2~n+1行是每家的位置及权重。

输入格式:输入测试数据集文件编号。

输出:

排序后X轴坐标

排序后X轴坐标对应权值

排序后Y轴坐标

排序后Y轴坐标对应的权值

邮局位置

三、算法设计

3.1问题描述:

       在一个按照东西和南北方向划分成规整街区的城市里,n个居民点散乱地分布在不同的街区中。用x坐标表示东西向,用y坐标表示南北向。各居民点的位置可以由坐标(x,y)表示。要求:为建邮局选址,使得n个居民点到邮局之距离的总和最小。

3.2解题思路:

带权中位数,就是给定的n个有序的数,每个数都有一个权值d[i](i=1,2,3,….,n)。此时的中位数就不再是第n/2个数了,而是这个数 i=1ndi2。中位数可以看做是权值为1的带权中位数。最优位置的选择与距离无关,设最优位置在t,则有t左面的权值和加上d[t]后大于右面的权值和,而类似的也有右面的权值和加上d[t]后大于左面的权值和。

因此要找到的点也就是满足以上条件的点。此时选择已经和具体的位置(坐标)没有关系了,成为主要考虑因素的仅仅是各点上的权值。最优位置上的数,就是这个序列中的带权中位数,所以这类问题,实质上就是带权中位数的问题。

对n个城市的x和y坐标分别排序,排序后的横坐标带权中位数和纵坐标带权中位数,即为邮局的最佳位置。

3.3数据结构的选择:

       由上述分析可知:可以使用两个一维int数组来分别定义坐标的x轴,y轴取值。另外,由于每个位置的代价不同,所以使用两个一维double数组来分别定义坐标的x轴,y轴的权重。

三个方法:

  1. 快速排序(同时将每个点对应的权值依次做调整)

public static void kuaipai(int[] a, double[] weight, int low, int height)

参数:a[]:待排序数组(轴上点坐标),weight[]:权值,param low:待排序数组最低点,param height:待排序数组最高点。

  1. 对每个轴求带权中位数对应的坐标

public static int dqzws(int [] address, double [] weights, String zhou)         

参数:address:轴上坐标,weights:权重,zhou:X或Y轴标识,return 带权中位数。

  1. 求邮局坐标(整合x和y轴)

           public static void zuobiao(int[] xaxis, int[] yaxis, double [] xweights, double[] yweights)

           参数:xaxis: x轴坐标点集,yaxis :y轴坐标点集,xweights:权重,yweights:权重

四、算法详细描述:

       4.1步骤:

  1. 选择测试文件
  2. 读取数据
  3. 定义居民点坐标以及每个点对应的权重
  4. 对x轴快速排序
  5. x轴相对应的权值随着轴做对应调整,使其保持一一对应
  6. 求x所有居民点权值之和
  7. 求x轴方向的带权中位数
  8. 对y轴快速排序
  9. y轴相对应的权值随着轴做对应调整,使其保持一一对应
  10. 求y轴所有居民点权值之和
  11. 求y轴方向的带权中位数
  12. 输出邮局位置

4.2代码:

import java.util.Scanner;

import java.io.*;

/**

 * 类名为Address

 *

 */

public class Address {

         /**

          * 主函数

          */

         public static void main(String[] args) throws Exception {

                   while(true){

                            /*

                             * 输入

                             */

                            System.out.println("请输入数据文件编号(1/3/4/5/6/7):");

                            Scanner sc = new Scanner(System.in);

                            int num = sc.nextInt();

                            /*

                             * 对用户输入进行合法性判断

                             */

                            if(num<=0 || num>7 || num==2){

                                     System.out.println("编号错误,请重新输入!(1/3/4/5/6/7)");

                                     continue;

                            }

                            /*

                             * 读取用户指定文件

                             */

                            BufferedReader br = new BufferedReader(new FileReader("F:/RYT/算法/第一次作业/S201961186assgin01/input_assgin01_0" + num + ".dat"));

                            String s = null;

                            /*

                             * 定义居民点坐标以及每个点对应的权重

                             */

                            int size = Integer.parseInt(br.readLine());//第一行的数字代表有几个居民

                            int[] x = new int[size];//创建int型x坐标数组

                            int[] y = new int[size];//创建int型y坐标数组

                            double[] xweight = new double[size];//创建double型x轴权重数组

                            double[] yweight = new double[size];//创建double型y轴权重数组

                           

                            int i = 0;

                            while((s = br.readLine()) != null){

                                     String[] a = s.split(","); //以,分割数据

                                    

                                     x[i] = Integer.parseInt(a[0]);//第一列是居民i位置的x坐标

                                     y[i] = Integer.parseInt(a[1]);//第二列是居民i位置的y坐标

                                     xweight[i] = Integer.parseInt(a[2]);//第三列是居民i位置的权重

                                     yweight[i] = Integer.parseInt(a[2]);

                                     i++;

                            }

                            /*

                             * 求解坐标

                             */

                            zuobiao(x, y, xweight, yweight);

                            //int postx = dqzws(x, xweight, "X");

                            //int posty = dqzws(y, yweight, "Y");

                            //System.out.println("\n邮局位置:\n(" + postx + "," + posty + ")");

                            System.out.println();

                   }

         }

         /**

          * 快排

          * @param a[]代拍数组

          * @param weight[]待排数组对应的权值

          * @param low左面的指针

          * @param height右面的指针

          */

         public static void kuaipai(int[] a, double[] weight, int low, int height){

                   int temp = 0;//坐标哨兵

                   double temp1 =0;//权值哨兵

                   int i = low;//左指针

                   int j = height;//右指针

                  

                   if(low < height){//数组里面有数

                           

                            temp = a[low];//设第一个为哨兵

                            temp1 = weight[low];



                            while(i != j){//i与j不相遇时

                                     while(j > i && a[j] >= temp) --j;

                                     if(i < j){

                                               a[i] = a[j];

                                               weight[i] = weight[j];

                                               ++i;

                                     }

                                     while(i < j && a[i] < temp) ++i;

                                     if(i < j){

                                               a[j] = a[i];

                                               weight[j] = weight[i];

                                               --j;

                                     }

                            }

                            a[i] = temp;

                            weight[i] = temp1;

                            kuaipai(a, weight, low, i - 1);

                            kuaipai(a, weight, i + 1, height);

                   }

         }

         /**

          * 对每个周求带权中位数对应的坐标

          * @param address  轴上的坐标

          * @param weights  权重

          * @param zhou  X或Y轴

          * @return 带权中位数

          */

         public static int dqzws(int [] address, double [] weights, String zhou){

                   /*

                    * 对每个轴坐标进行快速排序,权重的位置也跟上

                    */

                   kuaipai(address, weights, 0, address.length - 1);

                   System.out.println("\n排序后" + zhou + "轴坐标:");

                   for(int i = 0; i < address.length; i++) System.out.print(address[i] + " ");

                   System.out.println("\n排序后" + zhou + "轴坐标对应权值:");

                   for(int i = 0; i < weights.length; i++) System.out.print(weights[i] + " ");      

                   /*

                    * 所有居民点权值之和

                    */   

                   double sumweight = 0;

                   for(int i = 0; i < weights.length; i++) sumweight += weights[i];

                   //System.out.println("\n所有居民点权值之和:\n" + sumweight);

                   /*

                    * 求x/y轴方向的带权中位数

                    */

                   double sum = 0;

                   for(int i = 0; i < weights.length; i++){

                            sum += weights[i];

                            if(sum >= sumweight / 2) return address[i];

                   }

                   return 0;

         }

        

         /**

          * 求邮局坐标

          * @param xaxis  x轴坐标点集

          * @param yaxis  y轴坐标点集

          * @param xweights  x权重

          * @param yweights  y权重

          */

         public static void zuobiao(int[] xaxis, int[] yaxis, double [] xweights, double[] yweights){

                   /*

                    *对x轴坐标快排

                    */

                   int x = dqzws(xaxis, xweights, "X");

                   /*

                    *对y轴坐标快排

                    */

                   int y = dqzws(yaxis, yweights, "Y");

                   /*

                    *输出邮局的位置

                    */

                   System.out.println("\n邮局位置:\n(" + x + "," + y + ")");

         }

}

五、算法分析

由于快排时间复杂度为O(nlogn),求距离和时间复杂度为O(n),所以总复杂度为O(nlogn);

因为使用数组来保存坐标和权重,所以空间复杂度为O(n)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值