一、运行环境:
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轴的权重。
三个方法:
public static void kuaipai(int[] a, double[] weight, int low, int height)
参数:a[]:待排序数组(轴上点坐标),weight[]:权值,param low:待排序数组最低点,param height:待排序数组最高点。
public static int dqzws(int [] address, double [] weights, String zhou)
参数:address:轴上坐标,weights:权重,zhou:X或Y轴标识,return 带权中位数。
public static void zuobiao(int[] xaxis, int[] yaxis, double [] xweights, double[] yweights)
参数:xaxis: x轴坐标点集,yaxis :y轴坐标点集,xweights:权重,yweights:权重
四、算法详细描述:
4.1步骤:
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)。