面試筆試題——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; } } } } } }