售货员难题 状压dp

来源:互联网 发布:域名推广 编辑:程序博客网 时间:2024/04/29 23:38

售货员难题

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]);}



0 0
原创粉丝点击