HDU 3001 Traveling(状压DP)

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

原代码链接:http://blog.csdn.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
",ans);
    }
    return 0;
}

  


原文地址:https://www.cnblogs.com/s1124yy/p/5520986.html