HDU 3001 Travelling(状态压缩DP+三进制)

时间:2025-03-19 17:33:20

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001

题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上,要求经过所有城市并且花费最少,求出最小花费。

解题思路:三进制的状态压缩DP,跟二进制还是有一点不一样的,因为三进制没有直接的位运算,还要自己先做处理利用num[i][j]记录数字i各位的三进制表示方便计算,其他的就跟二进制状态压缩没有太大区别了。还有注意:

     ①开始要将n个起点初始化,dp[bit[i]][i]=0

     ②有重边,要去重

代码:

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=6e4+; int n,m,ans;
int map[][];
int dp[N][];
int bit[]={,,,,,,,,,,};
int num[N][]; //计算所有数字10位以内三进制表示
void make_tab(){
for(int i=;i<bit[];i++){
int b=i;
for(int j=;j<;j++){
num[i][j]=b%;
b/=;
}
}
} int main(){
make_tab();
while(~scanf("%d%d",&n,&m)){
memset(map,0x3f,sizeof(map));
memset(dp,0x3f,sizeof(dp));
int ans=INF;
for(int i=;i<=m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
a--,b--;
//去重边
map[a][b]=min(map[a][b],c);
map[b][a]=min(map[b][a],c);
}
for(int i=;i<n;i++)
dp[bit[i]][i]=;//对每个点定位初始点0 for(int i=;i<bit[n];i++){
bool flag=true;//表示所有位都是>=1,也就是每个城镇都走过了
for(int j=;j<n;j++){
if(num[i][j]==)
flag=false;
if(dp[i][j]==INF)//判断是否走到j点
continue;
for(int k=;k<n;k++){
//注意这个num[i][k]>=2,因为如果i状态在k点已经走过两次了显然是不能继续往下走的
if(j==k||num[i][k]>=||map[j][k]==INF)
continue;
int next=i+bit[k];//从j点走到k点
dp[next][k]=min(dp[next][k],dp[i][j]+map[j][k]);
}
}
//如果所有城镇都走了一遍则可以找出最小值
if(flag){
for(int j=;j<n;j++)
ans=min(ans,dp[i][j]);
}
}
if(ans==INF)
puts("-1");
else
printf("%d\n",ans);
}
return ;
}