思路:
- 首先要求出多源最短路,floyd直接上
- 然后是我们要求的,哈密顿回路的一个变种,咱们的题目要求的是把每个点都走一遍回到起点,但是与哈密顿回路不同的是,每个点可以走多次。(所以可以用floyd先把所有边都压缩一边)
- 所以我们需要一个代表状态的数,本题最多11个点,所以我们至少需要11位的二进制数来表示。第i位代表着第i个节点是否已经走过。
- 除了需要已经走过的信息,我们还需知道当前的位置,所以加一维。
dp[s][i]
表示在s的状态下,当前在i点所走的最短距离。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;
int n;
int dp[(1L<<11)+10][14];
int a[22][22];
void floyd(){
for(int k = 0;k <= n;k++){
for(int i = 0;i <= n;i++){
for(int j = 0;j <= n;j++){
if(a[i][j] > a[i][k] + a[k][j]){
a[i][j] = a[i][k] + a[k][j];
}
}
}
}
}
int main(){
while(~scanf("%d",&n),n){
for(int i = 0;i <= n;i++){
for(int j = 0;j <= n;j++){
scanf("%d",&a[i][j]);
}
}
floyd();
int flag = (1<<(n+1)) - 1;
memset(dp,0x3f,sizeof(dp));
for(int i = 0;i <= n;i++){
dp[1][i] = a[0][i];
}
int s;
for(s = 1;s <= flag;s++){
for(int i = 0;i <=n;i++){
if(s == (1<<i)) dp[s][i] = a[0][i];
for(int j = 0;j <=n;j++){
if(i!=j && (s&(1<<j)))
dp[s][i] = min(dp[s&(~(1<<j))][j]+a[j][i],dp[s][i]);
}
}
}
int ans = 0x7f7f7f7f;
for(int i = 0;i <= n;i++){
ans = min(ans,dp[s-1][i]+a[i][0]);
}
printf("%d\n",ans);
}
return 0;
}