进阶指南---最短Hamilton路径(状态压缩dp)

题目为带权无环图,要将每个点都走恰好一遍,问最短路径-----为旅行商问题
那要怎么搞呢,看了别人的题解发现,其无非就只有两个关键点:
1.一个为当前走过了哪些点
2. 目前是哪个点 ( f[ i ][ j ] )

走过了哪些点,n最大为20,不难想到可以用二进制的位来模拟,1则走过,0则还没走,关键在于转移:考虑上一步?哦吼,走了哪个点?那是不是就是 i 中 二进制表示下为1的位都有可能为上一个点 ?那现在又准备走那步勒?不就是i 中 二进制表示下为0的位都有可能为当前准备走的点???
那不就出来拉~
if ( ( i >> j ) & 1) // 用 j 表示找到的上一步的点
if ( ~(i >> k) & 1) // 用k表示目前看上准备走的点
转移不就是 :
f [i + ( 1 << k ) ] [ k ] = min( f[ i + ( 1 << k ) ] [ k ] ,f[ i ][ j ] + dis [ j ][ k ] )
// f[ i + ( 1<<k ) ] 看不懂?不会吧,你不会认为傻傻地在原地不动就能改变什么吧,肯定走了就要把k那位赋值为1啊,默默的付出是没啥人会注意的,要大声说出来兄弟
还有要 注意看代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 21,M = 1<<21;
int f[M][N],dis[N][N];
//f[i][j] i表示走过了哪些路,j表示最后一步是哪 
int main()
{
	int n;
	scanf("%d",&n);
	memset(f,0x3f,sizeof(f));//初始化类似于正无穷大10^9 
	for (int i = 0; i < n; i++){
		for (int j = 0; j < n; j++){
			scanf("%d",&dis[i][j]);
		}
	}
	f[1][0] = 0;//表示初始化时只有一个数走到自己为0,防循环不进 
	for (int i = 0; i < 1<<n; i++){
		for (int j = 0; j < n; j++){
			if((i>>j)&1)//j已经被走过
			{//假定j为上一步 
				for (int k = 0; k < n; k++){
					if(~(i>>k)&1)//这步还没人走
					{//指定为最后一步 
						f[i+(1<<k)][k] = min(f[i+(1<<k)][k],f[i][j]+dis[j][k]); 
					 } 
				}
			 } 
		}
	} 
	cout<<f[(1<<n)-1][n-1];
	return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值