面试笔试题——12个工厂分布

面试笔试题——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;
					}
				}
			}
		}
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值