hdu3001(状压dp)

 

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

题意:n 个城市已经 m 条路 以及对应路费 c,要求遍历所有城市最少的路费,每个城市不能超过2次。

分析:和TSP问题差不多,只不过变成三进制的状压,dig[i][j]表示在状态i下在点j已经做过的次数,dp[i][j]表示在状态i下到达点j走过的最小的路程,于是我们可以通过预处理得到dig[i][j]数组,然后就是一般的状态转移。

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <queue>

#include <cstdlib>

#include <stack>

#include <vector>

#include <set>

#include <map>

#define LL long long

#define mod 100000000

#define inf 0x3f3f3f3f

#define eps 1e-9

#define N 100010

#define FILL(a,b) (memset(a,b,sizeof(a)))

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

using namespace std;

int dp[60000][12];

int p[12],dig[60000][12];

int n,m,g[12][12];

void init()

{

    p[1]=1;

    for(int i=2;i<=11;i++)p[i]=p[i-1]*3;

    for(int i=0;i<p[11];i++)

    {

        int t=i;

        for(int j=1;j<=10;j++)

        {

            dig[i][j]=t%3;

            t/=3;

        }

    }

}

int main()

{

    init();

    while(scanf("%d%d",&n,&m)>0)

    {

        FILL(g,0x3f);FILL(dp,0x3f);

        for(int i=1;i<=m;i++)

        {

            int u,v,w;

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

            g[u][v]=g[v][u]=min(g[u][v],w);

        }

        int ans=inf;

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

        for(int s=0;s<p[n+1];s++)

        {

            int flag=1;

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

            {

                if(!dig[s][i])flag=0;

                if(dp[s][i]==inf)continue;

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

                {

                    if(i==j||dig[s][j]==2)continue;

                    if(g[i][j]==inf)continue;

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

                }

            }

            if(flag)

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

                ans=min(dp[s][i],ans);

        }

        if(ans==inf)puts("-1");

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

    }

}
View Code

 

你可能感兴趣的:(HDU)