HDU 3001 Travelling (三进制状压dp)

来源:互联网 发布:iphone6导出视频mac 编辑:程序博客网 时间:2024/05/22 00:18

题意

n(n<=10)个城市,知道每个城市间的旅行费用,但每个城市最多走两遍。问最小花费是多少 。

也就是每个城市可以走两次的tsp问题。


分析

最多走两次,三进制0 1 2可满足,即用三进制状压。与二进制不同的地方就是先要预处理三进制,并且还要用flag记录是否访问了所有节点。详见代码。


代码

#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<vector>#include<cctype>#include<set>#include<map>#include<queue>#include<stack>#include<iomanip>#include<sstream>#include<limits>#define ll long long#define inf 0x3f3f3f3fusing namespace std;const ll INF = 1e18;const int maxn = 2e5+10;const ll MOD = 1000000007;const double EPS = 1e-10;const double Pi = acos(-1.0);int G[110][110],dp[60000][12],tir[60000][12],s[12];int main(){#ifdef LOCAL    freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);    //freopen("output.txt","w",stdout);#endif//ios_base::sync_with_stdio(0);    int n,m;    s[0] = 1;    for(int i = 1; i <= 10; i++) s[i] = s[i-1]*3;    for(int i=0; i<=s[10]; i++)  //三进制记录 i状态下节点j经过的次数    {        int t=i;        for(int j = 0; j < 10; j++)        {            tir[i][j]=t%3;            t/=3;        }    }    while(scanf("%d%d",&n,&m)!=EOF)    {        memset(dp,inf,sizeof dp);        memset(G,inf,sizeof G);        for(int i = 0; i < n; i++) dp[s[i]][i] = 0;  //可从任何一点开始出发         for(int i = 0; i < m ;i++)         {             int u,v,w;             scanf("%d%d%d",&u,&v,&w);             u--;v--;             G[u][v] = G[v][u] = min(w,G[u][v]);         }         int ans = inf;         for(int i = 0; i < s[n]; i++)         {             bool flag = true;    //判断是否经过所有点             for(int j = 0; j < n; j++)             {                 if (tir[i][j] == 0) flag = false;                 if (dp[i][j] == inf) continue;                 for(int k = 0; k < n; k++)                 {                     if (j == k || tir[i][k] == 2) continue;  //节点k走过两次                     if (G[k][j] == inf) continue;                     dp[i+s[k]][k] = min(dp[i+s[k]][k],dp[i][j] + G[j][k]);                 }             }             if (flag)                for(int k = 0; k < n; k++)  ans = min(ans,dp[i][k]);         }         if (ans == inf) puts("-1");         else printf("%d\n",ans);    }    return 0;}
0 0