POJ3311(TSP问题,状态压缩DP)

题目链接:http://poj.org/problem?id=3311

分析:由于题中明确说了两个城市间的直接可达路径(即不经过其它城市结点)不一定是最短路径,所以需要借助邻接矩阵首先求出任意两个城市间的最短距离(因为这里的点可以多次遍历,并没有次数限制,所以才能用floyd的,如果有次数限制x的话,就不能用floyd预处理,而应该用x进制的状态压缩了)。这一步骤使用Floyd最短路径算法即可。然后,在此基础上来求出遍历各个城市后回到出发点的最短路径的距离,即求解TSP问题。

考虑搜索算法:这种解法其实就是计算排列子集树的过程。从0点出发,要求遍历123点后回到0点。以不同的顺序来依次遍历123点就会导出不同的路径(0->1->2->3->00->1->3->2->0等等),总共有3!=6条路径需要考虑,从中选出最短的那条就是所求。搜索解法的时间复杂度为 O(n!) 

思索:仔细观察搜索解法的过程,其实是有很多重复计算的。比如从0点出发,经过12345点后回到0点。那么0->1->2->(345三个点的排列)->00->2->1->(345三个点的排列)->0存在重复计算(345三点的排列)->0路径集上的最短路径。只要我们能够将这些状态保存下来就能够降低一部分复杂度。

状态保存:设集合 S 为一个点集,从 0 点出发,经过集合 S 中的每一个点,再回到出发点。那么怎样表示集合 S 呢?集合 S 是所有点所组成的集合的子集,那么得到集合 S 其实就是子集生成,二进制!
考虑 DP :记 dp [S][ i ] 0 点出发,到达集合 S 中的每一个点并且 i 是所遍历的最后一个点的( 0 点)的最短距离。
状态转移方程: dp [S][ i ] = min( dp [S][ i ], dp [S’][j]+a[j][ i ]) S’ 表示 S 的不包含 i 的子集, a[j][ i ] 表示从 j i 的最短距离。

边界条件: dp [S][ i ] = a[0][ i ] S 为只包含点 i 时的状态。
最终结果: min( dp[(1< )
#include
using namespace std;

int dp[65540][20];
int a[20][20];

int main()
{
    int n;

    while (cin>>n && n)
    {
        for (int i=0; i<=n; i++)
            for (int j=0; j<=n; j++) cin>>a[i][j];

        for (int k=0; k<=n; k++)
            for (int i=0; i<=n; i++)
                for (int j=0; j<=n; j++)
                    a[i][j] = min(a[i][j],a[i][k]+a[k][j]);

        int m = (1<


你可能感兴趣的:(状态压缩DP)