zoukankan      html  css  js  c++  java
  • 状态压缩DP:旅行商问题

    题目描述:给定一个n个顶点组成的带权有向图的距离矩阵d( i , j ) ( INF表示没有边 )。要求从顶点0出发,经过每个顶点恰好一次后再回到顶点0.问所经过的边的总权重的最小值是多少?

    限制条件:

    • 2 <= n <= 15
    • 0 <= d( i , j ) <= 1000

    题目解析:

    这个问题就是著名的旅行商问题(TSP)。所有可能的路线有(n-1)!种。这是一个非常大的值,即使题中n已经很小了,仍然无法试遍每一种情况。对于这个问题,我们可以使用DP来解决,首先写出它的递推公式。

    假设现在已经访问过的顶点集合(起点0当作还未访问过的顶点)为S,当前所在的顶点为v,用dp[S][v]表示从v出发访问剩余的所有顶点,最终回到顶点0的路径的权重总和最小值。由于从v出发可以移动到任意一个节点u不属于S。因此有如下递推公式:

    • dp[V][0] = 0
    • dp[S][v] = min{ dp[ SU{u} ][u] + d(v,u) | u不属于S}

    由于在这个递推公式中,有一个下标是集合而不是普通的整数,因此需要稍加处理。我们可以把它编码成一个整数,或者给它定义一个全序关系并用二叉搜索树存储,从而可以使用记忆话搜索来求解,特别的,对于集合我们可以把没一个元素的选取与否对应到一个二进制位里,从而把状态压缩成一个整数,大大方便了计算与维护。

    代码实例:

    int n;
    int d[MAX_N][MAX_N];
    
    int dp[1 << MAX_N][MAX_N];
    
    int rec(int S,int v){
    	if(dp[S][v] >= 0)
    		return dp[S][v];
    	if(S == (1 << n) - 1 && v == 0)
    		return dp[S][v] = 0;//已经访问过所有节点并回到0节点 
    	int res = INF;
    	for(int u = 0;u < n;u++){
    		if(!(S >> u & 1))//u不在集合S中 
    		//下一步移动到顶点u 
    			res = min(res,rec(s | 1 << u,u) + d[v][u]);
    	}
    	return dp[S][v] = res;
    }
    
  • 相关阅读:
    毛坯房装修步骤/过程
    编译方向是个值得考虑的选择(转发)
    暖气片安装常识
    装修,别忘了水电改造图纸
    新年走起
    装修中期需要实时监督 水电防水墙体拆改提前核定
    【CF1558D】TopNotch Insertions
    【洛谷P5008】锦鲤抄
    【UOJ#26】Game
    directx学习笔记之四:LPD3DXSPRITE,屏幕输出图片
  • 原文地址:https://www.cnblogs.com/long98/p/10352221.html
Copyright © 2011-2022 走看看