题目描述
给定一张 n ( n < = 20 ) n(n<=20) n(n<=20)个点的带权无向图,点从 0 n − 1 0~n-1 0 n−1标好 ,求起点 0 0 0到终点 n − 1 n-1 n−1的最短 h a m i l t o n hamilton hamilton路径
h a m i l t o n hamilton hamilton路径的定义是从 0 0 0到 n − 1 n-1 n−1不重不漏地经过每一个点恰好一次。
输入
第一行 n n n
接下来一个 n ∗ n n*n n∗n的邻接矩阵, a [ i ] [ j ] a[i][j] a[i][j]表示从点i到点j的点的距离
输出
一行,最短 h a m i l t o n hamilton hamilton路径长度
样例
样例输入1
2
0 1
1 0
样例输出1
1
solution
首先暴力,想到每个点进行
d
f
s
dfs
dfs
但是!
搜索的时间复杂度是
O
(
n
!
)
O(n!)
O(n!),考虑优化
我们注意到每个时刻
若知道哪些点已被走过和目前所在的点
就可做出下一步决策
而决策与这些点被走过的顺序无关
令
F
[
i
]
[
S
]
F[i][S]
F[i][S] 表示已经走过的点的集合是
S
S
S,当前所在点为
i
i
i时路径长度最小值
表示集合的方式:
将
S
S
S当作是一个
n
n
n位二进制数,第
i
i
i个点被走过,当且仅当
S
S
S的二进制第
i
i
i位是 1
求解对象:
F
[
n
]
[
(
1
<
<
n
)
−
1
]
F[n][(1<<n) -1]
F[n][(1<<n)−1],表示已经走过了所有点
AC code
int main(){
cin.tie(0);
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
memset(dp,0x3f,sizeof(dp));
dp[1][1]=0;//只选1 of course 为0
for(int j=1;j<(1<<n);j++){
for(int i=2;i<=n;i++){
if((1<<(i-1))&j)continue;//状态j已经包含i
for(int k=1;k<=n;k++){
if(k==i)continue;//dp[i][j]:此次选i,状态为j时的长度
dp[i][j+(1<<(i-1))]=min(dp[i][j+(1<<(i-1))],dp[k][j]+a[k][i]);
}
}
}
cout<<dp[n][(1<<n)-1];//选完了
return 0;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。