最短哈密顿环 退火_hdu 5418 Victor and World (最短哈密顿回路)

本文介绍了解决一个旅行商问题的算法,通过Floyd-Warshall方法预处理任意两点间的最短距离,然后使用动态规划求解从1号国家出发经过每个国家至少一次再返回的最短路径,总复杂度为O(n^3+n^2*2^n)。
摘要由CSDN通过智能技术生成

给你n个国家,m条路线:u_i与v_i之间的距离w_i。

输出从1号国家出发经过每个国家至少一次再回到1号国家的最短距离。

【官方题解】:

我们首先需要预处理出任意两个国家之间的最短距离,因为数据范围很小,所以直接用Floyd就行了。

之后,我们用f[S][i]表示访问国家的情况为S,当前最后访问的一个国家是i所需要的最小总油量,其中,S的二进制表示记录了访问国家的情况,S在二进制表示下的第i位(不管是从左往右还是从右往左都可以)。如果是1则表示第i个国家被访问过了,否则表示第i个国家没有被访问过。

如dp[13][3](13=1101表示现有城市1、3、4)表示从城市1到城市3的最短路(可能经过城市4)。

那么状态转移方程:

f[S|(1<

其中,S这个状态不包含i城市但包含j城市。即i和j满足S&(1<

最开始时,除了f[1][1]是0,其他情况都是无穷大,之后先枚举S,再枚举i(我验题的时候因为这里搞反结果WA了),那么最终的答案就是

min(f[(1<

总复杂度为O(n^3+n^2*2^n)

#include

#include

#include

#include

#include

#include

#include

#include

#include

typedef long long ll;

using namespace std;

const int inf=0x3f3f3f3f;

const int maxn=1e6+10;

int m,n;

int g[20][20];

int dp[maxn][20];

void floyd(){

for(int k=1;k<=n;++k){

for(int i=1;i<=n;++i){

for(int j=1;j<=n;++j){

g[i][j]=min(g[i][j],g[i][k]+g[k][j]);

}

}

}

}

int main()

{

int t;

scanf("%d",&t);

while(t--){

memset(g,inf,sizeof g);

scanf("%d %d",&n,&m);

int u,v,w;

for(int i=0;i

scanf("%d %d %d",&u,&v,&w);

if(g[u][v] > w){

g[u][v]=g[v][u]=w;

}

}

if(n == 1){

cout<<0<

continue;

}

floyd();

for(int i=1;i<=n;++i)g[i][i]=0;

memset(dp,inf,sizeof dp);

dp[1][1]=0;

for(int s=1;s< (1<

for(int i=1;i<=n;++i){

if(s&(1<

for(int j=1;j<=n;++j){

if( (s&(1<

int tt= (s | (1<

dp[tt][j]=min(dp[tt][j],dp[s][i]+g[i][j]);

}

}

}

}

}

//printf("%d\n",g[n][1] );

int ans=inf;

for(int i=2;i<=n;i++)

ans=min(ans,dp[ (1<

printf("%d\n",ans);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值