状压DP
其实状压DP网上讲解一抓一大把。个个都比我的详细易懂。所以我就不介绍这些东西了。我主要讲一些小技巧,以及自己对状压的理解。
理解
状压还是dp,所以关键就是找出状态转移方程。通常都是这个式子:
[f[yet][state | yet]=minlbrace f[have][state]+dis[have][yet]
brace
]
(have) 表示已经选的点, (yet) 表示还未选的点。一般枚举已选子集
优化
- 枚举子集
for(int i=S;i;i=(i-1)&S)
具体证明详见 这篇博客 。 - 对于已经选和未选的点,可以用数组
have[]
,yet[]
保存,以空间换时间。当然也可以用lowbit()
操作和log2()
配合使用。 - 初值
比如
int N=(1<<T)-1;
for(int i = 1;i <=T;i++){
f[i][1<<(i-1)]=dis[0][point[i].first][point[i].second];
}
for(rint i = 0;i <= N;i++){//枚举当前状态
c1=c2=0;
for(rint j = 1;j <= T;j++){
if(1<<(j-1) & i) have[++c1]=j;
else yet[++c2]=j;
}
for(rint j = 1;j <= c1;j++)//已选
for(rint h = 1;h <= c2;h++){//未选
if(f[yet[h]][i|(1<<(yet[h]-1))] > f[have[j]][i]+dis[have[j]][yet[h]]){
f[yet[h]][i|(1<<(yet[h]-1))] = f[have[j]][i]+dis[have[j]][yet[h]];
}
}
}