题意:
游戏园里有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 }