现在的位置: 首页 > 综合 > 正文

HDU 3001 Travelling ( 状态压缩 )

2019年02月23日 ⁄ 综合 ⁄ 共 1448字 ⁄ 字号 评论关闭

题目链接~~>

做题感悟:以前也做过类似的题目,但是这里规定每个地点只能访问 2 次 ,用二进制结果超内存,然后就百度了一下原来用三进制。

解题思路:

                大体的思路还是和 TSP 差不多,只是这里一个地点可以最多拜访两次 ,用三进制就可以解决这个问题,但是三进制不如二进制好处理。因为每个地点最多可以拜访两次,so ~> 不可以用Floyd 预处理。先预处理出来三进制的各个状态,以及各个状态的各位的状态。dp[ S ] [ i ] 代表达到状态 S 后到达 i 最小花费。

             动态方程: dp [ S + t [ j ] ] [ j ] = min (dp [ S +  t [ j ] ] [  j  ] , dp[ S ]  + d [ i ] [ j  ] )  ;  

代码:

#include<iostream>
#include<fstream>
#include<iomanip>
#include<ctime>
#include<fstream>
#include<sstream>
#include<stack>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#define INT __int64
using namespace std ;
const double esp = 0.00000001 ;
const int INF = 0x3f3f3f3f ;
const int mod = 1e9 + 7 ;
const int MY = 10 + 10 ;
const int MX = 59049+ 10 ;
int n ,m ;
int t[MY] ,dp[MX][MY] ,d[MY][MY] ,f[MX][MY] ;
void init() // 预处理状态
{
    t[0] = 1 ;
    for(int i = 1 ;i <= 11 ; ++i)
        t[i] = t[i-1] * 3 ;
    for(int S = 0 ; S <= 59049 ; ++S)
    {
        int temp = S ,i = 0 ;
        while(temp)
        {
            f[S][i++] = temp % 3 ;
            temp /= 3 ;
        }
    }
}
void input()
{
   int u ,v ,w ;
   memset(d ,INF ,sizeof(d)) ;
   for(int i = 0 ;i < m ; ++i)
   {
       scanf("%d%d%d" ,&u ,&v ,&w) ;
       u-- ; v-- ;
       d[u][v] = d[v][u] = min(d[u][v] ,w) ;
   }
}
void DP()
{
    int best = INF ;
    memset(dp ,INF ,sizeof(dp)) ;
    for(int i = 0 ;i < n ; ++i)
       dp[t[i]][i] = 0 ;
    for(int S = 0 ;S < t[n] ; ++S)
    {
        bool flag = true ; // 查看是否每个地点都拜访过了
        for(int i = 0 ;i < n ; ++i)
        {
          if(dp[S][i] != INF)
          {
            for(int j = 0 ;j < n ; ++j)
              if(i != j && f[S][j] <= 1 && d[i][j] != INF)
              {
                  int& ans = dp[S+t[j]][j] ;
                  ans = min(ans ,dp[S][i] + d[i][j]) ;
              }
           }
           if(!f[S][i]) flag = false ;
          }
          if(flag)
                 for(int i = 0 ;i < n ; ++i)
                     best = min(best ,dp[S][i]) ;
    }
    if(best != INF)
              cout<<best<<endl ;
    else      cout<<"-1"<<endl ;
}
int main()
{
    init() ;
    while(~scanf("%d%d" ,&n ,&m))
    {
        input() ;
        DP() ;
    }
    return 0 ;
}

抱歉!评论已关闭.