面试笔试题——12个工厂分布
12个工厂分布在一条东西向高速公路的两侧,工厂距离公路最西端的距离分别是0、4、5、10、12、18、27、30、31、38、39、47.在这12个工厂中选取3个原料供应厂,使得剩余工厂到最近的原料供应厂距离之和最短,问应该选哪三个厂 ?(需注意不知道工厂的分布情况!)
上面是在群里面贴出来的,自己就收藏了一下,想等有空的时候想想。下面我就解这道题的思路说一下,有不对的地方还请指出。
首先要注意在12个工厂中有一个到最西端的为0,我设这一点为第0个工厂,我们可以看到每个工厂都是离最西端一点的距离,那么我们是不是可以将这个问题这样理解?就是所有节点以最西端为圆心的一个圆,那么第0个工厂就是在圆心位置(因为它离最西端为零),那么就可以将上面的问题描述成下面的一个图:
个人认为这个工厂位置可以通过上图描述出来。那么得到这样一个图如何求选择哪三个工厂作为原料厂呢?下面将进行讲解:
我们假设原则的三个原料厂为p、q、r。那么所有节点到离其最进的原料厂的距离之和为最小时,则这三个厂为原料厂。要求得图中每个节点到其的最短距离这是一个Dijkstra算法,所以此处需要对图中所有节点求一次Dijkstra算法,我们通过一个Map来存储,Map的key为当前Dijkstra的源点,值为通过Dijkstra算得的dist[]数组。此时我们就得到了所有节点的Dijkstra的dist[]数组,并将其进行存储在Map中。那么如何取得三个原料厂呢?那就是从这12个厂中任选三个,并求的所有节点到离其最近的原料厂的距离之和,我们将这个和赋给一个tempmin变量。如何任选三个工厂,那么就需要使用三重循环,其实这里是个排列组合,那么共有12*12*12种,但注意还要减去不能选择相同工厂的情况,就是通过一个if判断来避免选择相同工厂的情况,当我们任选了三个工厂作为原料厂,那么就需要求的所有节点(但必须出去已被选定作为原料厂的工厂)到和其最近的原料厂距离之和,同时赋给tempmin,注意该变量是记录每任取三个原料的距离之和。取得每次的距离之和在进行比较,将会产生一个最短的情况,那么这种情况的所选的三个原料厂是最好的情况。详细代码如下:(解题方法仅供参考!如有不足欢迎讨论!)
public class Factory{ /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub float[][] a = new float[12][12]; for (int i = 0; i < 12; i++) { for (int j = 0; j < 12; j++) { if (i == j) { a[i][j] = 0; } else { a[i][j] = Float.MAX_VALUE; } } } a[0][1] = 4; a[1][0] = 4; a[0][2] = 5; a[2][0] = 5; a[0][3] = 10; a[3][0] = 10; a[0][4] = 12; a[4][0] = 12; a[0][5] = 18; a[5][0] = 18; a[0][6] = 27; a[6][0] = 27; a[0][7] = 30; a[7][0] = 30; a[0][8] = 31; a[8][0] = 31; a[0][9] = 38; a[9][0] = 38; a[0][10] = 39; a[10][0] = 39; a[0][11] = 47; a[11][0] = 47; Float[] dist = new Float[12]; int[] prev = new int[12]; Map<String, Float[]> distMap = new HashMap<String, Float[]>(); List<Float[]> list = new ArrayList<Float[]>(12); for (int i = 0; i < 12; i++) { //System.out.print(i+"--->"); dijkstra(i, a, dist, prev); distMap.put(i+"f", dist); /*for(int j=0; j<12; j++) { System.out.print(dist[j]+" "); } System.out.println();*/ dist = new Float[12]; //System.out.println(); } float min = Float.MAX_VALUE; int p = -1, q=-1, r=-1; Map<String, Float[]> tempMap = new HashMap<String, Float[]>(); for (int i = 0; i < 12; i++) { for (int j = 0; j < 12; j++) { for (int k = 0; k < 12; k++) { if(i!=j&&i!=k&&j!=k) { tempMap.put(i+"y", distMap.get(i+"f")); tempMap.put(j+"y", distMap.get(j+"f")); tempMap.put(k+"y", distMap.get(k+"f")); float tempmin = 0.0f; for (int m = 0; m < 12; m++) { float temp = Float.MAX_VALUE; if (m != i && m != j && m != k) { //取得当前的点到当前所选的三个原料厂中那个地点最短 for (Map.Entry<String, Float[]> entry : tempMap .entrySet()) { if (temp > entry.getValue()[m]) { temp = entry.getValue()[m]; } } //此处是求的当前所选的三个节点,所有节点到和其最进的节点距离之和 tempmin+=temp; } } tempMap.clear(); //比较整个最小 System.out.println("最小和为: "+tempmin+"三个原料厂为:"+i+" "+j+" "+k); if(min>tempmin) { min=tempmin; p=i; q=j; r=k; } } } } } System.out.println("最小和为: "+min+"三个原料厂为:"+p+" "+q+" "+r); } public static void dijkstra(int v, float[][] a, Float[] dist, int[] prev) { int n = dist.length - 1; if (v < 0 || v >n) return; boolean[] s = new boolean[n + 1]; //此处的循环是初始化 for (int i = 0; i <= n; i++) { dist[i] = a[v][i]; s[i] = false; if (dist[i] == Float.MAX_VALUE) prev[i] = -1; else prev[i] = v; } //此处开始遍历 dist[v] = 0.0f; s[v] = true; //该循环是求的所有节点到源节点的路径,每循环一次求的一个节点到源节点的距离 for (int i = 0; i <=n; i++) { float temp = Float.MAX_VALUE; int u = v; //shortestPath(此处取该循环为shortestPath) for (int j = 0; j < n; j++) { if ((!s[j]) && (dist[j] < temp)) { u = j; temp = dist[j]; } } //System.out.print(u+" dist:"+dist[u]+" "); s[u] = true; //updateDist(取名为updateDist) for (int j = 0; j <=n; j++) { if ((!s[j]) && (a[u][j] < Float.MAX_VALUE)) { float newdist = dist[u] + a[u][j]; if (newdist < dist[j]) { dist[j] = newdist; prev[j] = u; } } } } } }