利用分治算法进行邮局选址(java实现)

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

package postaddress;
import java.util.Scanner;
import java.io.*;

public class PostAddress {
	public static void main(String[] args) throws Exception {
		while(true){
			
			//选择要输入的测试数据文件的编号
			System.out.println("请输入数据文件编号(1~5):");
			Scanner sc = new Scanner(System.in);
			int num = sc.nextInt();
			if(num<=0 || num>=6){
				System.out.println("编号错误请重新输入(1~5)!");
				continue; 
			}
			
			//读取数据
			FileReader fr = new FileReader("D:\\Program Files (x86)\\MyStudy\\src\\postaddress\\input\\input_assign01_0"+num+".dat");
			BufferedReader br = new BufferedReader(fr);
			String s = null;
			int size = Integer.parseInt(br.readLine());
			
			//定义居民点坐标及对应的权重
			int[] x = new int[size];
			int[] y = new int[size];
			double[] xweight = new double[size];
			double[] yweight = new double[size];
			int i = 0;
			while((s = br.readLine()) != null){
				String[] a = s.split(",");	//输入的数据文件中坐标与权重用","分隔开		
				x[i] = Integer.parseInt(a[0]);
				y[i] = Integer.parseInt(a[1]);
				xweight[i] = Integer.parseInt(a[2]);
				yweight[i] = Integer.parseInt(a[2]);
				i++;
			}
			zuobiao(x, y, xweight, yweight);
			System.out.println();
		}
	}
	
//快速排序
public static void qSort(int[] a, double[] weight, int low, int height){// a:待排序数组;   weight:权值;     low:待排序数组最低点;     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){
				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;
			qSort(a, weight, low, i - 1);
			qSort(a, weight, i + 1, height);
		}
	}
	
//对每个轴坐标进行快速排序,同时调整对应的权重
	public static int axis(int []addr, double [] Weights, String zhou){
		qSort(addr, Weights, 0, addr.length - 1);
		System.out.println("排序后的" + zhou + "轴坐标为:");
		for(int i = 0; i < addr.length; i++){
			System.out.print(addr[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);
		
		//求带权中位数
		for(int i = 0; i < Weights.length; i++){
			sumweight += Weights[i];
			if(sumweight >= sumweight / 2){ return addr[i]; }
		}
		return 0;
	}
	
	//求邮局坐标
	public static void zuobiao(int[] Xaxis, int[] Yaxis, double [] XWeights, double[] YWeights){//Xaxis:x轴坐标点集;   Yaxis:y轴坐标点集;   XWeights:权重;   YWeights:权重
        int px = axis(Xaxis, XWeights, "X");//对x轴坐标点进行快速排序
		int py = axis(Yaxis, YWeights, "Y");//对y轴坐标点进行快速排序
		System.out.println("邮局位置为:\n(" + px + "," + py + ")");//打印满足条件的邮局位置
	}
}


编程语言:Java

运行环境:Win10、MyEclipse

运行过程说明:根据提示信息输入要测试的数据文件的编号(1-5),数据文件中第一行为居民个数,后面的每行是居民位置坐标及权值,其中居民位置横、纵坐标、权值用","分隔(如:1,2,3)。输入数据文件的编号后程序开始运行,依次输出排序后的x、y轴坐标及对应权值,最后输出满足距离最小条件的邮局位置。

伪码描述:输入数据文件的编号;
利用FileReader、BufferedReader读取数据;
利用void qSort()对每个轴坐标进行快速排序,同时调整对应的权重;
求带权中位数:
for(int i = 0; i < Weights.length; i++){
sumweight += Weights[i];
if(sumweight >= sumweight / 2){
return addr[i]; }
}
打印邮局坐标

算法设计:实质上是带权中位数问题。用两个一维整型数组来分别定义x轴、y轴坐标取值,由于每个位置的代价不同,使用两个一维double数组来分别定义坐标的x轴、y轴的权重。先进行快速排序,同时依次调整每个点对应的权值,求出x、y轴的带权中位数坐标,最后打印出邮局坐标。

算法分析:快速排序的时间复杂度为O(nlogn)
求距离总和为O(n)
总的时间复杂度为O(nlogn)

运行情况:
input_assign01_01.dat中的数据为:
6
1,1,3
3,5,6
9,-5,9
7,-18,24
8,9,5
10,0,6
在这里插入图片描述

发布了32 篇原创文章 · 获赞 23 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_35443700/article/details/102960122