最短Hamilton路径
题目描述
给定一张 n(n \leq 20)(n≤20) 个点的带权无向图,点从0 \sim n-10∼n−1标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。
输入描述:
第一行一个整数n。
接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^710
7
的正整数,记为a[i,j])。
对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且a[x,y]+a[y,z] \geq a[x,z]a[x,y]+a[y,z]≥a[x,z]。
输出描述
一个整数,表示最短Hamiltn路径
思路:
首先先将输入用数组w[i][j]存入,表示i到j的距离。
然后我们可以考虑用一个n位二进制数表示该点是否被经过,若第i位为1则被经过反之未被经过。还要知道当前是位于哪个点。所以可以用一个数组f[i][j](0<i<2^n,0=<j<n)表示点被经过的状态。二进制i对应于j表示目前处于j点i状态的最短路径。先将该数组的“起点”f[0][1]设为0,然后将其余值全部设为最大值0x3f。最终得到的结果是f[1<<n-1,n-1],即当前状态经过了所有点,而且到达了终点。用循环遍历数组f[i][j],在i(二进制)的j位为1的情况下用一个变量k来遍历i的所有点,即将i的j位(取反)赋值为0后遍历i的每一位,考虑这样的k,取(f[i][j],f[i^1<<j][k]+w[k][j])的最小值,就能得到从k到j的最短路径。
完整代码:
#include<iostream> #include<string.h> #include<cmath> using namespace std; int w[21][21],n; int f[1 <<20][20]; int Hamilton() { memset(f, 0x3f, sizeof(f)); f[1][0] = 0; for (int i = 1; i < 1 << n; i++) for (int j = 0; j < n; j++) if (i >> j & 1)//若i的j位为1 for (int k = 0; k < n; k++) if ((i ^ 1 << j) >> k & 1)//先将i的j位取反再看k位是否为1 f[i][j] = min(f[i][j], f[i ^ 1 << j][k] + w[k][j]);// return f[(1 << n) - 1][n - 1]; } int main() { cin >> n; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> w[i][j]; } } cout << Hamilton(); return 0; }