ch0103 位运算,状压dp

题意:n个顶点带权无向图,求最短hamilton路径长度(从起点0走到终点n-1,且经过每个顶点恰好一次的路径)

在看位运算的时候做到这题,觉得状态压缩的思路挺奇特的。本来n<20,O(n!*n)的算法肯定炸了,但是可以二进制表示状态。如果将i表示为二进制,i的第j位走过就为1,没走过就为0(注意二进制位从0~n-1),此处1<=i<2^n-1。用dp[i][j]表示状态i,到达第j个城市的最小值,那么i的二进制第j位为1(到达第j个城市),且i的二进制第j位取反之后,二进制第k位为1(没到达第j个城市前,到达过第k个城市)

满足这两个条件之后,转移方程为:dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+w[k][j]),

先把dp数组初始化为inf,再初始化dp[1][0]=0(开始在第0个城市),答案为dp[(1<<n)-1][n-1]。

#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=10;
int main()
{
	int n,i,j,k,t;
	int w[maxn][maxn];
	int dp[1<<maxn][maxn];
	cin>>n;
	for (i=0;i<n;i++)
	  for (j=0;j<n;j++)
	    cin>>w[i][j];
	memset(dp,inf,sizeof(dp));
	dp[1][0]=0;
	for (i=1;i<(1<<n);i++)
	  for (j=0;j<n;j++) if ((i>>j)&1)   //i的二进制第j位=1(当前二进制状态下,经过第j个城市) 
	    for (k=0;k<n;k++) if ((i^(1<<j))>>k&1) //第j位取反后,第k个城市走过 
	        dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+w[k][j]);
	cout<<dp[(1<<n)-1][n-1]<<endl; //+-的优先级比>>大... 
	return 0;
}

  

原文地址:https://www.cnblogs.com/edmunds/p/12300540.html