给定一个n个顶点的带权有向图的距离矩阵d(i,j)(INF表示没有边)。要求从顶点0出发,经过每个顶点恰好一次再回到顶点0,求所经过边的总权重的最小值。
这就是著名的旅行商问题(TSP,Travelling Salemans Problem)。TSP问题是NP困难的,没有已知的多项式时间的高效算法可以解决这一问题(别问我这是什么~~~~(>_<)~~~~)。不过在程序设计中数据比较小的题目还是可能出现的。所有可能的路线总共有(n-1)!种,可以用dp来解决。假设现在已访问过的顶点的集合为S(顶点0当做未访问的顶点),当前所在顶点为v,用dp[S][v]表示从v出发访问剩余的所有顶点,最终回到顶点0的路径的权重总和的最小值。由于从v出发可以移动到任意的一个顶点u(u不属于S),因此有如下递推式:dp[V][0]=0,dp[S][v]=min{dp[S+u][u]+d[v][u]}。用这个递推式就可以计算出所求结果。不过在递推式中有一个下标不是整数而是集合,对于集合我们可以把每个元素的选取与否对应到一个二进制位里,从而把状态压缩成一个整数,大大简化了计算和维护。忘记说了,想学好状压dp,首先要熟练掌握位运算╮(╯_╰)╭。(这是在《挑战程序设计竞赛》里看到的)
直接贴代码了。
#include<iostream>
#include<cstring>
using namespace std;
#define INF 1e9
#define maxn 20
int dp[1<<maxn][maxn];
int n=5;
int d[maxn][maxn]={
{INF,3,INF,4,INF},
{INF,INF,5,INF,INF},
{4,INF,INF,5,INF},
{INF,INF,INF,INF,3},
{7,6,INF,INF,INF}
};
int rec(int S,