Update:
1、C code refactoring
2、Add Java code
【问题描述】
某小区决定在小区内部建一家便利店,现小区内部共有八栋楼,它们的地理坐标分别为:(10,20)、(30,34)、(19,25)、(38,49.1)、(9,38.1)、(2,34)、(5,8)、(29,48)。同时,其中的住户人数分别为:30, 45, 28, 8, 36, 16, 78, 56。为了方便更多的住户购物,要求实现总体最优,请问便利店应该建立在哪里?
【提示】
1)便利店无论选址何处,八栋楼的居民均可直接到达,即八栋楼与便利店均相邻,且距离为直线距离;
2)八栋楼的居民人数为权重,应该方便大多数人,实现总体最优。
【解题思路】
通过对设计要求的分析。程序将由以下几个功能模块构成。
【算法描述】
1.地址坐标:
首先让我们假设出一张地图:为了简便,我们用A、B、C、D、E、F、G、H表示小区内部的八栋楼,设P为便利店。
我们将地图分割成若干等份:A、B、C、D、E、F、G、H分别在网格的格点上。
确立坐标:坐标原点为(0,0),设A点坐标为(X0,Y0),B点坐标为(X1,Y1),C点坐标为(X2,Y2),D点坐标为(X3,Y3),E点坐标为(X4,Y4),F点坐标为(X5,Y5),G点坐标为(X6,Y6),H点坐标为(X7,Y7),P点坐标为(Xp,Yp)。
2.距离计算函数:
由此,我们不难设计一个函数计算出AP、BP、CP、DP、EP、FP、GP、HP的长度。在不考虑权重的情况下,只要八者之和最短,则P点就为便利店所在地。但是,由于还要考虑人数对选址的影响,所以对数据进行如下处理:XA=X0*权重A;XB=X1*权重B;XC=X2*权重C;XD=X3*权重D;XE=X4*权重E;XF=X5*权重F;XG=X6*权重G;XH=X7*权重H;然后再从中选出使八者之和最小的P点!
3.近似最优求解模块:
由于P点的坐标是不确定的,所以P的值是变化的。考虑到实际情况下,超市不可能占地面积只有一个点。所以我们将P的精度取到1米,让D的坐标以1米为步长,其X,Y轴分别加1与各个单位求距离。
【代码实现】
1、C语言版
#include<stdio.h> #include<math.h> #define N 8 //结构体定义 struct chooseLocale { double x; double y; int w; double xp; double yp; } location[N]; double g_minX=0; double g_maxX=0; double g_minY=0; double g_maxY=0; double g_minSum=30000; double g_shopX=0; double g_shopY=0; int g_iCount=0; double get_length(double x,double y,double x1,double y1); void getEdgelocation(); void inputHouselocation(); void getShoplocation(); int main() { inputHouselocation(); getEdgelocation(); getShoplocation(); printf("count=%d\n",g_iCount);//打印sum计算次数 printf("minsum=%lf\n",g_minSum); printf("计算出便利店建立的地理坐标为:\nlocation(%lf,%lf)\n",g_shopX,g_shopY); return 0; } double get_length(double x,double y,double x1,double y1) { return(sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1))); } /* 输入各个单位坐标 (10,20,30) , (30,34,45) , (19,25,28) , (38,49.1,8) , (9,38.1,36) , (2,34,16) , (5,8,78) , (29,48,56) */ void inputHouselocation() { for(int i=0; i<N; i++) { printf("Please input House %d locationInfo :\n",i); scanf("%lf%lf%d",&location[i].x,&location[i].y,&location[i].w); } } /* 找到八个单位中坐标的边缘点,以缩小搜索范围。 */ void getEdgelocation() { for(int i=0; i<N; i++) { if(location[i].x<g_minX) { g_minX=location[i].x; } else { g_maxX=location[i].x; } if(location[i].y<g_minY) { g_minY=location[i].y; } else { g_maxY=location[i].y; } } } void getShoplocation() { struct chooseLocale cl; double len[8]= {0}; double sum=0; for(cl.xp=g_minX; cl.xp<=g_maxX; cl.xp++) { for(cl.yp=g_minY; cl.yp<=g_maxY; cl.yp++) { for(int i=0; i<N; i++) { len[i]=get_length(location[i].x,location[i].y,cl.xp,cl.yp); len[i]=len[i]*location[i].w; sum=sum+len[i]; g_iCount++; } if(sum<g_minSum) { g_minSum=sum; g_shopX=cl.xp; g_shopY=cl.yp; } sum=0; } } }
LocationInfo.java
/** * @author john * @created 2016-1-28 */ public class LocationInfo { private double mLocationX=0; private double mLocationY=0; private int mWeight=0; public double getLocationX() { return mLocationX; } public void setLocationX(double locationX) { mLocationX = locationX; } public double getLocationY() { return mLocationY; } public void setLocationY(double locationY) { mLocationY = locationY; } public int getWeight() { return mWeight; } public void setWeight(int weight) { mWeight = weight; } }
ShopVo.java
/** * @author john * @created 2016-1-28 */ public class ShopVo { private double mDistanceMinSum = 0; private double[] mShopLocation = { 0, 0 }; private int mCount = 0; public double getDistanceMinSum() { return mDistanceMinSum; } public void setDistanceMinSum(double distanceMinSum) { mDistanceMinSum = distanceMinSum; } public double[] getShopLocation() { return mShopLocation; } public void setShopLocation(double[] shopLocation) { mShopLocation = shopLocation; } public int getCount() { return mCount; } public void setCount(int count) { mCount = count; } }
import java.util.List; /** * @author john * @created 2016-1-28 */ public class CalculateShopLocale { private int mHouseNum = 0; private Double[] edgeMinLocation = new Double[2]; private double[] edgeMaxLocation = { 0, 0 }; private double[] distances = { 0,0}; private List<LocationInfo> mLocationInfoList = null; /** * 估算的最小距离 */ private double distanceMinSum = 0; /** * 构造函数初始化 mHouseNum , mLocationInfoList , distanceMinSum * */ public CalculateShopLocale(int mHouseNum, List<LocationInfo> mLocationInfoList, double distanceMinSum) { this.mHouseNum = mHouseNum; this.mLocationInfoList = mLocationInfoList; this.distanceMinSum = distanceMinSum; } /** * 获取两地距离 */ private double getTwoPositionDistance(double x, double y, double newX, double newY) { // TODO Auto-generated method stub double distance = Math.sqrt(Math.pow(newX - x, 2)+Math.pow(newY - y, 2)); return distance; } /** * 找到所有位置中坐标的边缘点,以缩小搜索范围 */ private void getEdgeLocation() { if (mLocationInfoList != null) { edgeMinLocation[0] = mLocationInfoList.get(0).getLocationX(); edgeMinLocation[1] = mLocationInfoList.get(0).getLocationY(); for (int i = 0; i < mHouseNum; i++) { if (mLocationInfoList.get(i).getLocationX() < edgeMinLocation[0]) { edgeMinLocation[0] = mLocationInfoList.get(i).getLocationX(); } else { edgeMaxLocation[0] = mLocationInfoList.get(i).getLocationX(); } if (mLocationInfoList.get(i).getLocationY() < edgeMinLocation[1]) { edgeMinLocation[1] = mLocationInfoList.get(i).getLocationY(); } else { edgeMaxLocation[1] = mLocationInfoList.get(i).getLocationY(); } } } } /** * 获取便利店最佳选址位置,并打印出该位置到所有住户最小距离和,同时打印出计算次数 */ public void getShopLocation(ShopVo sv) { System.out.println("CalculateShopLocale <<< mList = "+mLocationInfoList); getEdgeLocation(); double distanceSum = 0; double[] shopLocation = { 0, 0 }; int iCount = 0; for (double x = edgeMinLocation[0]; x <= edgeMaxLocation[0]; x++) { for (double y = edgeMinLocation[1]; y <= edgeMaxLocation[1]; y++) { for (int i = 0; i < mHouseNum; i++) { distances[i] = getTwoPositionDistance(mLocationInfoList.get(i).getLocationX(), mLocationInfoList.get(i).getLocationY(), x, y); distances[i] *= mLocationInfoList.get(i).getWeight(); distanceSum += distances[i]; iCount++; } if (distanceSum < distanceMinSum) { distanceMinSum = distanceSum; shopLocation[0] = x; shopLocation[1] = y; } distanceSum = 0; } } sv.setDistanceMinSum(distanceMinSum); sv.setCount(iCount); sv.setShopLocation(shopLocation); } }
import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * @author john * @created 2016-1-28 */ public class Main { /** * 住户数 */ private static final int HOUSE_NUM = 8; private static Scanner sc = new Scanner(System.in); /** * 控制台输入住户位置信息参数(x,y,w) * * (10,20,30) , (30,34,45) , (19,25,28) , (38,49.1,8) , (9,38.1,36) , * (2,34,16) , (5,8,78) , (29,48,56) * */ private static LocationInfo getHouseLocationItem(LocationInfo locationInfo) { System.out.println("Please input LocationX : "); double locationX = sc.nextDouble(); System.out.println("Please input LocationY : "); double locationY = sc.nextDouble(); System.out.println("Please input weight : "); int weight = sc.nextInt(); locationInfo.setLocationX(locationX); locationInfo.setLocationY(locationY); locationInfo.setWeight(weight); return locationInfo; } /** * 获取各个位置地理坐标和权值 */ private static List<LocationInfo> getHouseLocationList(LocationInfo locationInfo) { List<LocationInfo> list = new ArrayList<LocationInfo>(); for (int i = 0; i < HOUSE_NUM; i++) { System.out.println("Please input House " + i + " LocationInfo"); locationInfo = getHouseLocationItem(locationInfo); list.add(locationInfo); } return list; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub // 估算的最小距离 double distanceMinSum = 30000; ShopVo shopVo = new ShopVo(); LocationInfo locationInfo = new LocationInfo(); List<LocationInfo> mList = getHouseLocationList(locationInfo); System.out.println("Main <<< mList = " + mList); CalculateShopLocale csl = new CalculateShopLocale(HOUSE_NUM, mList, distanceMinSum); csl.getShopLocation(shopVo); sc.close(); System.out.println("计算总次数 : " + shopVo.getCount() + "\n" + "便利店最佳选址位置到所有住户最小距离和 : " + shopVo.getDistanceMinSum() + "\n" + "便利店建立的地理坐标 : " + shopVo.getShopLocation()); } }