您的位置:首页 > 其它

【算法学习笔记】62.状态压缩 DP SJTU OJ 1088 邮递员小F

2015-07-06 23:21 429 查看
状态压缩,当我们的状态太多时可以考虑用bit来存储,用二进制来表示集合,用&来取交集,用^来异或。

DP过程很简单,遍历所有情况取最短路径就行,因为最短哈密顿回路本身就是一个NPC问题,效率不高。

#include <vector>
#include <iostream>
using namespace std;

//最短哈密顿回路问题 NP完全问题。。。

int map[16][16]={0};
int n=0;

const int INF=768000;//3000*16*16
int f[1<<16][16]={0};//f[i][j]表示的是 从起点开始 经过所有i中的点 到达j的最短路径长度
void initialize(){
cin>>n;
for (int i = 0; i < n; ++i){
for (int j=0; j < n; ++j){
cin>>map[i][j];//输入数据
}
}
}

int build(){
// 起点始终在列表里 那个位置一直为1 所以不用考虑起点
// DP状态压缩 比如 n=4 时 eg: 1<<3 -->表示 1000 从 0000到 1000 确定了前面3个位置的所有情况
for (int i = 0; i < ( 1 << (n-1) ); ++i)//
{
//要注意 输入时下标为j的点 在i中的下标为j-1 简称j点
//DP计算 f[i][j]
for (int j = 1; j < n ; ++j){
if(i == ( 1 << (j-1) ))//如果此时i中正好只有j点的话
f[i][j] = map[0][j];//直接从起点到j即可
else{//否则需要dp
if(i & (1 << (j-1) ))//i中有j点
{
f[i][j] = INF;//开始寻找它的最小值
for( int k = 1; k < n ;  ++k)
if(k!=j and (i & ( 1<< (k-1) ) ) )
//找到k k不是j 且在i中
//状态转移方程如下 其实只是一个松弛操作而已 收边
f[i][j] = min(f[i^(1<<(j-1))][k] + map[k][j], f[i][j]);

}
}
}
}

int res = INF;
for (int i = 1; i < n; ++i)
{
res = min(res, f[(1<<(n-1))-1][i] + map[i][0]);
}
return res;
}

int main(int argc, char const *argv[])
{
initialize();
if(n==1)
cout<<2*map[0][0]<<endl;
else
cout<<build()<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: