设有m个城市,已知其中任何两个城市之间(不经过第三个城市)道路的距离。一个货郎需要到每个城市巡回卖货,他从某个城市出发,每个城市恰好经过一次,最后回到出发的城市。问怎样走使得总的路程最短。
问 题 : 有 穷 个 城 市 的 集 合 C = { c 1 , c 2 , … , c m } , 距 离 d ( C i , c j ) = d ( c j , c i ) ϵ Z + , 1 < = 1 < j < = m 求 1 , 2 , … , m 的 排 列 k 1 , k 2 , … , k m 以 求 得 最 小 值 m i n { ∑ i = 1 m − 1 d ( c k i , c k i + 1 ) + d ( c k m , c k 1 ) } 问题:有穷个城市的集合C=\lbrace c_1,c_2,\ldots,c_m \rbrace,距离d(C_i,c_j)=d(c_j,c_i)\epsilon Z^+,1<=1<j<=m\\求1,2,\ldots,m的排列k_1,k_2,\ldots,k_m以求得最小值min\{\sum_{i=1}^{m-1}{d(c_{k_i},c_{k_{i+1}})+d(c_{k_m},c_{k_1})}\} 问题:有穷个城市的集合C={c1,c2,…,cm},距离d(Ci,cj)=d(cj,ci)ϵZ+,1<=1<j<=m求1,2,…,m的排列k1,k2,…,km以求得最小值min{i=1∑m−1d(cki,cki+1)+d(ckm,ck1)}
下面给出问题的一个实例,即
C
=
{
c
1
,
c
2
,
c
3
,
c
4
}
,
d
(
c
1
,
c
2
)
=
10
,
d
(
c
1
,
c
3
)
=
5
,
d
(
c
1
,
c
4
)
=
9
,
d
(
c
2
,
c
3
)
=
6
,
d
(
c
2
,
c
4
)
=
9
,
d
(
c
3
,
c
4
)
=
3
C=\{c_1,c_2,c_3,c_4\},\quad d(c_1,c_2)=10,\quad d(c_1,c_3)=5,\\ \quad d(c_1,c_4)=9,\quad d(c_2,c_3)=6,\quad d(c_2,c_4)=9,\quad d(c_3,c_4)=3
C={c1,c2,c3,c4},d(c1,c2)=10,d(c1,c3)=5,d(c1,c4)=9,d(c2,c3)=6,d(c2,c4)=9,d(c3,c4)=3
实例代码如下:
public class Demo1_2 {
//D集合代表的是城市之间的距离,如D[1][2]代表的是,城市1和城市2之间的距离
private final static int[][] D = { { 0, 10, 5, 9 }, { 10, 0, 6, 9 },
{ 5, 6, 0, 3 }, { 9, 9, 3, 0 } };
//S集合代表的是除开始城市之外的其他城市的编号
private final static int[] S = { 2, 3, 4 };
/**
* 计算该条路径下走过的中距离
*
* @param S 经过城市的顺序
* @param startPosition 出发的城市的编号
* @return 经过的总距离
*/
private static int calculateDistance(int[] S, int startPosition) {
int sumDistance = 0;
int temp = startPosition;
for (int s : S) {
sumDistance += D[temp - 1][s - 1];
temp = s;
}
// 加上回到出发城市的距离
sumDistance += D[temp - 1][startPosition - 1];
return sumDistance;
}
/**
* 获得传入数组的全排列
*
* @param arr
* @return
*/
private static List<int[]> getAllElement(int[] arr) {
List<int[]> elements = new ArrayList<int[]>();
nextPer(arr, 0, elements);
return elements;
}
private static void nextPer(int[] arr, int start, List<int[]> elements) {
// 当start==arr.length-1时,说明子序列的长度为1,就不用再往下分子序列了
if (start == arr.length - 1) {
elements.add(cloneArray(arr));
return;
}
for (int i = start; i < arr.length; i++) {
// start代表的是每一个子序列的第一个位置,我们每一层递归的任务都只有一个:
// 枚举该层子序列第一个位置可以取的值
swop(arr, start, i);
// 该层递归的子序列第一个位置已经确定了,所以又可以往下再分
nextPer(arr, start + 1, elements);
// 把第该层子序列第一个位置的值换成另外一个值,所以要交换回来
swop(arr, start, i);
}
}
/**
* 将src的值拷贝到一个新的数组上,并返回
*
* @param src
* @return
*/
private static int[] cloneArray(int[] src) {
int[] dest = new int[src.length];
System.arraycopy(src, 0, dest, 0, src.length);
return dest;
}
// 交换数组中i和j对应位置的值
private static void swop(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
List<int[]> elements = getAllElement(S);
int minDistance = 0;
int minIndex = 0;
for (int i = 0; i < elements.size(); i++) {
int distance = calculateDistance(elements.get(i), 1);
System.out.println("路径" + Arrays.toString(elements.get(i))
+ "下,总的路程为:" + distance);
if (distance < minDistance) {
minDistance = distance;
minIndex = i;
}
}
System.out.println("其中总路程最短的方案是:"
+ Arrays.toString(elements.get(minIndex)));
}
}