hdu 4114 Disney's FastPass 状压dp

点击打开链接


题意:

游戏园里有N个区域,有M条边连接这N个区域,有K个要访问的景点。对于每个景点告诉你这个景点所在的区域,要访问这个景点需要等待一定时间,如果没有FastPass,等待时间有Ti,否则等待时间为FTi,接下来的Ni,表示有Ni个区域可以得到这个景点的FastPass,问从区域1出发,再回到区域1所需要的最少时间。


思路:

状态压缩,dis[i][s1][s2],表示当前走到这个点,s1表示拿到了哪些景点的FastPass,s2表示已经访问了哪几个景点。

但是需要注意的是:当游览过某个景点之后,就认为拿着了这个景点的票了!!!这个优化很重要

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m,k;
 5 int dis[55][55],dp[55][1<<8][1<<8],pos[10],t[10],ft[10],pas[55];
 6 int ans;
 7 
 8 void init(){
 9     ans = 0x3f3f3f3f;
10     memset(dp,0x3f,sizeof(dp));
11     memset(dis,0x3f,sizeof(dis));
12     memset(pas,0,sizeof(pas));
13 }
14 
15 void floyd(){
16     for(int k=1; k<=n; k++)
17         for(int i=1; i<=n; i++)
18             for(int j=1; j<=n; j++)
19                 dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
20 }
21 
22 void solve(){
23     dp[1][0][0] = 0;
24     for(int s1=0; s1<(1<<k); s1++){
25         for(int s2=0; s2<(1<<k); s2++){
26             for(int i=1; i<=n; i++){
27                 int now = dp[i][s1][s2];
28                 if(now==0x3f3f3f3f) continue;
29                 if(s2==(1<<k)-1) ans = min(ans,now+dis[i][1]);
30                 for(int j=0; j<k; j++){
31                     if((s2&(1<<j)) == 0){ // 没走过第j个景点
32                         int& nxt = dp[pos[j]][s1|pas[pos[j]]][s2^(1<<j)]; // 当游览过某个景点之后,就认为拿着了这个景点的票了!!!
33                         int add = dis[i][pos[j]];
34                         if(s1 & (1<<j)) add += ft[j];
35                         else add += t[j];
36                         nxt = min(nxt,now+add);
37                     }
38                 }
39                 for(int j=1; j<=n; j++){  // 中转 通过j得到fastpass
40                     int& nxt = dp[j][s1|pas[j]][s2];
41                     int add = dis[i][j];
42                     nxt = min(nxt,now+add);
43                 }
44             }
45         }
46     }
47 }
48 
49 int main(){
50     int T; cin>>T;
51     for(int cas=1; cas<=T; cas++){
52         
53         init();
54         cin >> n >> m >> k;
55         for(int i=1; i<=m; i++){
56             int u,v,w; cin>>u>>v>>w;
57             dis[u][v] = w; dis[v][u] = w;
58         }
59         for(int i=0;i<n;i++) dis[i][i]=0; 
60         floyd();
61 
62         for(int i=0; i<k; i++){
63             cin >> pos[i] >> t[i] >> ft[i];
64             int num; cin>>num;
65             for(int j=0; j<num; j++){
66                 int tmp; cin>>tmp;
67                 pas[tmp] |= (1<<i);
68             }
69         }
70 
71         solve();
72 
73         cout << "Case #" << cas << ": " << ans << endl;
74 
75     }
76 }

 

转载于:https://www.cnblogs.com/yxg123123/p/6827730.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值