HDU 4114 Disney's FastPass(floyd+状态压缩DP)

来源:互联网 发布:臭氧灯能除螨虫知乎 编辑:程序博客网 时间:2024/05/16 15:48

Disney's FastPass

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2419    Accepted Submission(s): 670


Problem Description

Disney's FastPass is a virtual queuing system created by the Walt Disney Company. First introduced in 1999 (thugh the idea of a ride reservation system was first introduced in world fairs), Fast-Pass allows guests to avoid long lines at the attractions on which the system is installed, freeing them to enjoy other attractions during their wait. The service is available at no additional charge to all park guests.
--- wikipedia



Disneyland is a large theme park with plenties of entertainment facilities, also with a large number of tourists. Normally, you need to wait for a long time before geting the chance to enjoy any of the attractions. The FastPass is a system allowing you to pick up FastPass-tickets in some specific position, and use them at the corresponding facility to avoid long lines. With the help of the FastPass System, one can arrange his/her trip more efficiently.
You are given the map of the whole park, and there are some attractions that you are interested in. How to visit all the interested attractions within the shortest time? 
 

Input
The first line contains an integer T(1<=T<=25), indicating the number of test cases.
Each test case contains several lines.
The first line contains three integers N,M,K(1 <= N <= 50; 0 <= M <= N(N - 1)/2; 0 <= K <= 8), indicating the number of locations(starting with 1, and 1 is the only gate of the park where the trip must be started and ended), the number of roads and the number of interested attractions.
The following M lines each contains three integers A,B,D(1 <= A,B <= N; 0 <= D <= 10^4) which means it takes D minutes to travel between location A and location B.
The following K lines each contains several integers Pi, Ti, FTi,Ni, Fi,1, Fi,2 ... Fi,Ni-1, FiNi ,(1 <= Pi,Ni, Fi,j <=N, 0 <= FTi <= Ti <= 10^4), which means the ith interested araction is placed at location Pi and there are Ni locations Fi,1; Fi,2 ... Fi,Ni where you can get the FastPass for the ith attraction. If you come to the ith attraction with its FastPass, you need to wait for only FTi minutes, otherwise you need to wait for Ti minutes.
You can assume that all the locations are connected and there is at most one road between any two locations.
Note that there might be several attrractions at one location.
 

Output
For each test case in the input, print one line: "Case #X: Y", where X is the test case number (starting with 1) and Y is the minimum time of the trip.
 

Sample Input
24 5 21 2 82 3 43 4 194 1 62 4 72 25 18 1 34 12 6 1 34 6 21 2 51 4 43 1 13 2 13 4 12 4 102 8 3 1 44 8 3 1 2
 

Sample Output
Case #1: 53Case #2: 14
 

Source
2011 Asia ChengDu Regional Contest 
 

Recommend
We have carefully selected several similar problems for you:  4119 4118 4115 4112 4111 
 

题目大意:

    在一个图上有一些景点,游玩每个景点需要花费一定的时间排队,每个景点在一些地方有优惠票,拿着对应景点的优惠票游玩排队时间可以变为另一个时间,在图上的不同地点移动需要不同的时间。问从一个顶点游玩所有顶点后返回所需的最短时间。


解题思路:

    第一眼看上去就会觉得这题和TSP问题很像,实际上解题方法也是类似的。

    对于这种在有环图上dp的题目,由于环会使得dp数组重复更新,大部分时候我们要通过一定的方法回避在环上的更新。

    dp[i][s1][s2]表示当前在点i,已经去过s1状压点景点,已经拿到s2状压的票。为了避免在图上的环中重复的更新,我们先用floyd得到任意两点之间的最短距离,然后就可以从小的状态不断用刷表法向后转移了。转移有两种。1、到一个没有游玩过的点游玩。2、移动到一个地方,并拿到那个地方的票。最后当游玩所有顶点时,加上回到起点的时间更新答案。


AC代码:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <cstdlib>#include <cmath>#include <string>#include <map>#include <stack>#include <ctime>#include <set>using namespace std;#define INF 0x3f3f3f3f#define LL long long#define fi first#define se second#define mem(a,b) memset((a),(b),sizeof(a))const int MAXN=50+3;const int MAXK=8;struct Edge{    int to,cost;    Edge(int t,int c):to(t),cost(c){}};int N,M,K;int G[MAXN][MAXN];//邻接矩阵int p[MAXN],t[MAXN],ft[MAXN];int ticket[MAXN];//第i个地方有的票的状态int dp[MAXN][1<<MAXK][1<<MAXK];//当前在i,已经去过s1,有s2的票时最小的时间花费void init()//初始化{    for(int i=0;i<N;++i)        for(int j=0;j<N;++j)            G[i][j]=(i==j?0:INF);    mem(ticket,0);    mem(dp,0x3f);}int main(){    int T;    scanf("%d",&T);    for(int cas=1;cas<=T;++cas)    {        scanf("%d%d%d",&N,&M,&K);        init();        for(int i=0;i<M;++i)        {            int u,v,c;            scanf("%d%d%d",&u,&v,&c);            G[u-1][v-1]=G[v-1][u-1]=c;        }        for(int k=0;k<N;++k)//floyd预处理出所有点之间的距离            for(int i=0;i<N;++i)                for(int j=0;j<N;++j)                    G[i][j]=min(G[i][j],G[i][k]+G[k][j]);        for(int i=0;i<K;++i)        {            int n;            scanf("%d%d%d%d",&p[i],&t[i],&ft[i],&n);            --p[i];            for(int j=0;j<n;++j)            {                int tmp;                scanf("%d",&tmp);                --tmp;                ticket[tmp]|=1<<i;            }        }        int ans=INF;        dp[0][0][0]=0;        for(int s1=0;s1<(1<<K);++s1)//已经访问的点            for(int s2=0;s2<(1<<K);++s2)//已经拿到的票                for(int now=0;now<N;++now)//当前位置                    if(dp[now][s1][s2]!=INF)                    {                        if(!(s1^((1<<K)-1)))//全部景点都已经去过,返回起点,更新答案                        {                            ans=min(ans,dp[now][s1][s2]+G[now][0]);                        }                        for(int i=0;i<K;++i)//去游玩                            if(!(s1&(1<<i)))                            {                                int &next=dp[p[i]][s1|(1<<i)][s2|ticket[p[i]]];                                if(s2&(1<<i))                                    next=min(next,dp[now][s1][s2]+G[now][p[i]]+ft[i]);                                else next=min(next,dp[now][s1][s2]+G[now][p[i]]+t[i]);                            }                        for(int i=0;i<N;++i)//到处走拿票                        {                            int &next=dp[i][s1][s2|ticket[i]];                            next=min(next,dp[now][s1][s2]+G[now][i]);                        }                    }        printf("Case #%d: %d\n",cas,ans);    }        return 0;}


1 0
原创粉丝点击