售货员难题
Description
某乡有n个村庄(1<=n<=14),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0< s<1000)是已知的,且A村到B村与B村到A村的路程大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在地,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程之和最短。请你帮他选择一条最短的路。
Input Format
村庄数n和各村之间的路程(均是正整数)。
Output Format
最短的路程
Sample Input
4 {村庄数}0 30 6 4 {村庄1到各村的路程}6 5 0 20 {村庄3到各村的路程}30 0 5 10 {村庄2到各村的路程}4 10 20 0 {村庄4到各村的路程}
Sample Output
25
题目分析:经典的TSP问题。给定一张带权有向图,求从第一个节点出发又返回一的最小花费。我们可以用f[i][j]表示状态为j的节点i的最小花费。 例如f[5][3]就表示节点0和节点2回到3时的最小花费。状态转移:
单点集:状态存在dp[1<<j][j] = 0;否则无穷大。
非单点集:
状态存在 dp[i][j] = min(dp[k][s] + w[s][j])
k表示i集合中去掉了j点的集合,s遍历集合k中的点并且dp[k][s]状态存在,点s到点j有边存在,w[s][j]表示边的权值。
状态不存在 dp[i][j]为无穷大。
最后的结果是:
min( dp[( 1 << n ) – 1][j] ) ( 0 <= j < n );#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #include<cmath> #include<cctype> #include<cassert> #include<climits> using namespace std; #define For(i,n) for(int i=1;i<=n;i++) #define Rep(i,n) for(int i=0;i<n;i++) #define Fork(i,k,n) for(int i=k;i<=n;i++) #define ForD(i,n) for(int i=n;i;i--) #define Forp(x) for(int p=pre[x];p;p=next[p]) #define RepD(i,n) for(int i=n;i>=0;i--) #define MEM(a) memset(a,0,sizeof(a)) #define MEMI(a) memset(a,127,sizeof(a)) #define MEMi(a) memset(a,128,sizeof(a)) #define INF (2139062143) #define phiF (1000000006) #define MAXN (1000000+10) typedef long long LL; int n,a[20][20],f[20][50000]; int main(){ scanf("%d",&n); For (i,n) For (j,n) scanf("%d",&a[i][j]); int num=(1<<n)-1; MEMI(f); f[1][0]=0; For (j,num) For (i,n){ if (j&(1<<i-1)) For (k,n) if (k!=i) f[i][j]=min(f[i][j],f[k][j-(1<<i-1)]+a[i][k]); } printf("%d",f[1][num]); }