HDU 3001 Traveling(状压DP)

时间:2023-07-09 19:57:56

题目大意:10个点的TSP问题,但是要求每个点最多走两边,不是只可以走一次,所以要用三进制的状态压缩解决这个问题。可以预处理每个状态的第k位是什么。

原代码链接:http://blog.****.net/accry/article/details/6607703

3进制,代表走过这个点的次数

#include <cstdio>
#include<cstdlib>
#include <cstring>
#define INF 0x1f1f1f1f
#define min(a,b) (a) < (b) ? (a) : (b)
using namespace std; int N,M;
int tri[12] = {0,1,3,9,27,81,243,729,2187,6561,19683,59049};
int dig[59050][11]; //dig[state][k_dig] 状态state的第k位是多少
int edge[11][11],dp[59050][11]; int main()
{
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Zmy\\Desktop\\in.txt","r",stdin);
// freopen("C:\\Users\\Zmy\\Desktop\\out.txt","w",stdout);
#endif // ONLINE_JUDGE //
// char stit[200];
// for (int i=0;i<12;i++)
// {
// itoa(tri[i],stit,3);
// puts(stit);
// } for(int i = 0; i < 59050; ++i)
{
int t = i;
for(int j = 1; j <= 10; ++j)
{
dig[i][j] = t%3;
t /= 3;
if(t == 0)break;
}
} // itoa(123,stit,3);
// puts(stit);
//
// puts("tst");
// for(int j = 1; j <= 10; ++j)
// printf("%d ",dig[123][j]); while(scanf("%d%d",&N,&M) != EOF)
{
memset(edge,INF,sizeof(edge)); int a,b,c;
int m2=M;
while(M --)
{
scanf("%d%d%d",&a,&b,&c);
if(c < edge[a][b])edge[a][b] = edge[b][a] = c;
} // for (int i=1;i<=N;i++)
// {
// for (int j=1;j<=N;j++)
// printf("%d ",edge[i][j]);
// puts("");
// } memset(dp,INF,sizeof(dp)); for(int i = 1; i <= N; ++i)dp[tri[i]][i] = 0; int ans = INF;
for(int S = 0; S < tri[N+1]; ++S)
{
int visit_all = 1;
for( int i = 1; i <= N; ++i)
{
if(dig[S][i] == 0)visit_all = 0;
if(dp[S][i] == INF)continue; for(int j = 1; j <= N; ++j)
{
if(i == j)continue;
if(edge[i][j] == INF ||dig[S][j] >= 2)continue;
int newS = S + tri[j];
dp[newS][j] =min(dp[newS][j],dp[S][i] + edge[i][j]);
}
} if(visit_all)
{
for(int j = 1; j <= N; ++j)
ans = min(ans,dp[S][j]);
} } if(ans == INF)
{
puts("-1");
continue;
}
printf("%d\n",ans);
}
return 0;
}