/*
S表示已经走过的城市,1表示已经走过,0表示未走过(位标记集合)
首先对于原图进行floyd,得到一个最短路的图(16^3,绰绰有余啊)
然后遍历所有的集合
f[x][S]中,x表示完成S集合时,最后走到的是x,然后储存的值就是到这样的状态需要的最小花费。
可能觉得奇怪,假如一开始进行floyd,那么a->b就变成a->c->b,那么在a已入的情况下加入b,那c不是可以直接加入的吗?
不要慌,a->c->b,就是a—>c,c->b,这两条不会被改变(就算被改变,继续递归下去想吧),就不会丢掉c了。
方程:f[x][S]=min(f[x][S],f[k][S^(1<<(x-1))]+_map[k][x]){其中,k已经在S中}
最后不要忘了加_map[x][0],要回去的233
*/
#include <iostream>
#include <cstdio>
using namespace std;
int n;
int f[16][66000],_map[16][16];
int main()
{
cin>>n;
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
scanf("%d",&_map[i][j]);
}
}
//floyd
for(int k=0;k<=n;k++){
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
if(i!=j&&i!=k&&j!=k){
if(_map[i][k]+_map[k][j]<_map[i][j])
_map[i][j]=_map[i][k]+_map[k][j];
}
}
}
}
int Smax=(1<<n)-1;
for(int S=1;S<=Smax;S++){
for(int i=1;i<=n;i++){
if(S&(1<<(i-1))){
if( (S^(1<<(i-1))) ==0){
f[i][S]=_map[0][i];
}else{
f[i][S]=99999999;
for(int j=1;j<=n;j++){
if(S&(1<<(j-1)) && i!=j){
f[i][S]=min(f[i][S],f[j][S^(1<<(i-1))]+_map[j][i]);
}
}
}
}
}
}
int ans=99999999;
for(int i=1;i<=n;i++){
ans=min(ans,f[i][Smax]+_map[i][0]);
}
cout<<ans;
return 0;
}
covs 2800 送外卖
最新推荐文章于 2020-05-02 17:39:49 发布