hdu 4284 Travel (floyd + 状态 dp 2012 ACM/ICPC Asia Regional Tianjin Online )

http://acm.hdu.edu.cn/showproblem.php?pid=4284

题意:

题目:给出一些城市,从1出发,旅游一圈回到1,由于花费可能不够,所以选择一些城市打工,打工之前需要花费d买一个证,工资为c。选中的城市必须去工作一次,而且只能工作一次,问能不能完成旅行

 

这道 题 比赛是想的是  先 floyd  在 暴搜 ,结果 tle  赛后 看到  有人 暴搜 过了 ,,,,好无语(自己 考虑的 情况太多了)。。。。。。

题解:

首先 因为 我们 要用到的 只有 H 个点,所以我们先用 floyd 处理一下 ,构建一个 新图 ,在新图上处理,枚举 所有状态

 

首先 暴搜 的 时间复杂度为 O(15 !),要超啊,状态压缩  O(H * H * 2^H);可以接受 ;

dp[sta][i] 表示  状态  sta  最后一个工作的 节点 为 i   所剩的 最多钱数

 

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include< set>
  7 #include<map>
  8 #include<queue>
  9 #include<vector>
 10 #include< string>
 11  #define Min(a,b) a<b?a:b
 12  #define Max(a,b) a>b?a:b
 13  #define CL(a,num) memset(a,num,sizeof(a));
 14  #define eps  1e-12
 15  #define inf 100000
 16 
 17  // freopen("data.txt","r",stdin);
 18  const  double pi  = acos(- 1.0);
 19 typedef   __int64  ll;
 20  using  namespace std;
 21  int H,n,m,mon,sta,st;
 22  int dp[ 1 <<  17][ 20] ,mat[maxn][maxn],a[ 20];
 23  struct node
 24 {
 25      int ci;
 26      int di ;
 27 }p[maxn] ;
 28  void floyd()
 29 {
 30      for( int k =  1;k<=n;k++)
 31     {
 32          for( int i =  1;  i <= n;i++ )
 33         {
 34              for( int  j =  1; j<= n;j++)
 35             {
 36                  if(mat[i][j] > mat[i][k] +  mat[k][j])
 37                 {
 38                     mat[i][j] = mat[i][k] + mat[k][j] ;
 39                 }
 40             }
 41         }
 42     }
 43 
 44 }
 45  void solve()
 46 {
 47      sta =  1 << H ;
 48      int  i,j,k;
 49     CL(dp,- 1);
 50 
 51      for(i =  1;i<=H;i++) //  注意这 每一次 要 从  1 开始  出发,H 中 有没有 1  无所谓 
 52      {
 53          int tp = mon - mat[ 1][a[i]] - p[i].di ;
 54          if(tp >=  0)
 55          dp[ 1<<(i -  1)][i] = tp + p[i].ci ;
 56     }
 57 
 58      for(i =  0 ;i < sta;i++)
 59     {
 60          for(j =  1;j<=H;j++)
 61         {
 62              if(dp[i][j] <  0) continue ;
 63 
 64              int u = a[j] ;
 65 
 66              if(i &  1 <<(j -  1) ==  0) continue ;
 67 
 68 
 69            for(k =  1;k<=H;k++)
 70           {
 71                int v = a[k];
 72                if(i &  1 << (k -  1)) continue ;
 73 
 74                int t = i |  1 <<(k -  1) ;
 75 
 76                if(dp[i][j] >= mat[u][v] + p[k].di)
 77               {
 78                    if(dp[t][k] < dp[i][j] - mat[u][v] - p[k].di + p[k].ci);
 79                   dp[t][k] = dp[i][j] - mat[u][v] - p[k].di  + p[k].ci;
 80               }
 81 
 82 
 83           }
 84         }
 85     }
 86 }
 87  void init()
 88 {
 89      for( int i =  0 ; i <= n;i++)
 90     {
 91          for( int j =  0 ;j<= n;j++)
 92         {
 93            mat[i][j] =inf ;
 94              if(i == j)
 95             {
 96                  mat[i][j] =  0;
 97             }
 98         }
 99     }
100 }
101  int main()
102 {
103      // freopen("data.txt","r",stdin);
104       int t,i,j,x,y,len;
105     scanf( " %d ",&t);
106      while(t--)
107     {
108         scanf( " %d%d%d ",&n,&m,&mon);
109         init() ;
110          for(i =  0 ;i< m;i++)
111         {
112             scanf( " %d%d%d ",&x,&y,&len);
113              if(mat[x][y] > len)
114             mat[x][y] = mat[y][x] = len ;
115         }
116         floyd() ;//在原图上 构建的新图
117 
118         scanf( " %d ",&H);
119          int  f =  0;
120          for(i =  1 ;i<= H;i ++ )
121         {
122             scanf( " %d %d %d ",&a[i],&p[i].ci,&p[i].di);
123            
124         }
125 
126 
127        
128         solve();
129         int flag =  0;
130 
131          for(i =  1 ; i<= H;i++)
132         {
133              if(dp[sta -  1][i] >= mat[a[i]][ 1])
134             {
135 
136                 flag =  1;
137                  break ;
138             }
139         }
140          if(flag)puts( " YES ");
141          else puts( " NO ");
142     }
143 }

转载于:https://www.cnblogs.com/acSzz/archive/2012/09/12/2682207.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值