HDU 4114 Disney's FastPass(状压dp)

来源:互联网 发布:管家婆普及版数据恢复 编辑:程序博客网 时间:2024/06/06 00:39

题意就是给你一些点,有的地方有景区,有的地方有某些景点的优先票,拿优先票去景点和不拿的时间不一样。问从地点1出发去所有景点再回来的最短时间。

得把景点,景区进行状压。即dp[i][j][k]代表参观景点状态为i,景区状态为j,停在k的最短时间。

先floyd一下处理出最短路。

对于一种状态i,j,为了保证dp[i][j][k]在递推的时候是最短时间可以先用2个(1-n)for循环进行更新,因为可能有的位置的状态是-1即不存在。事实上只要有一个点存在i与j的状态,那么其他点必定都存在i,j这个状态。

然后再去更新去看景点的情况,在做过刚才那个处理后,其实只需要看当前位置下的景点就行,看网上其他人的代码则是遍历去看所有景点,如果这样做的话就不用先做那个处理了,可以放在一起做。

另外,还有一个优化,如果已经参观了那个节点,那么就强行给他一个票,其实就是在其他条件都相同的情况下(在同一个点,经过同样的景点),有票跟没票的比较。这样的话,参观景点的集合就是票的集合的子集了。然后又容易看出其实i跟j的递推顺序交换也是一样的,所以就用了枚举子集的办法,然后把子集从小到大推。

竟然刷到rank1了。577ms。

AC代码:

#include<cstdio>#include<ctype.h>#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cstdlib>#include<stack>#include<queue>#include<set>#include<map>#include<cmath>#include<ctime>#include<string.h>#include<string>#include<sstream>#include<bitset>using namespace std;#define ll __int64#define ull unsigned long long#define eps 1e-8#define NMAX 1<<29#define MOD 1000000#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define PI acos(-1)template<class T>inline void scan_d(T &ret){    char c;    int flag = 0;    ret=0;    while(((c=getchar())<'0'||c>'9')&&c!='-');    if(c == '-')    {        flag = 1;        c = getchar();    }    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();    if(flag) ret = -ret;}int dp[1<<8][1<<8][55],dist[55][55];struct node{    int t,ft;};node no[10];inline void update(int &a, int b){    if(a < 0 || a > b)        a = b;}void floyd(int n){    for(int k = 1; k <= n; k++)        for(int i = 1; i <= n; i++)            for(int j = 1; j <= n; j++)                dist[i][j] = min(dist[i][j],dist[i][k]+dist[k][j]);}int pos[10],getft[55];int s[1<<8];int main(){#ifdef GLQ    freopen("input.txt","r",stdin);//    freopen("o.txt","w",stdout);#endif    int t,n,m,K,cas = 1;    scanf("%d",&t);    while(t--)    {        scanf("%d%d%d",&n,&m,&K);        for(int i = 1; i <= n; i++)        {            for(int j = 1; j <= n; j++)                dist[i][j] = NMAX;            dist[i][i] = 0;        }        for(int i = 1; i <= m; i++)        {            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            dist[u][v] = dist[v][u] = w;        }        floyd(n);        memset(getft,0,sizeof(getft));        for(int i = 0; i < K; i++)        {            int tmp;            scanf("%d%d%d%d",&pos[i],&no[i].t,&no[i].ft,&tmp);            while(tmp--)            {                int t1;                scanf("%d",&t1);                getft[t1] |= (1<<i);            }        }        for(int i = 0; i < (1<<K); i++)            for(int j = 0; j < (1<<K); j++)                for(int k = 1; k <= n; k++) dp[i][j][k] = -1;        dp[0][0][1] = 0;        for(int j = 0; j < (1<<K); j++)        {            int nct = 0;            for(int i = j; i ; i = (i-1)&j) s[nct++] = i;            s[nct++] = 0;            for(int w = nct-1; w >= 0; w--)            {                int i = s[w];                for(int k = 1; k <= n; k++) if(dp[i][j][k] >= 0)                {                    for(int l = 0; l < K; l++) if(!(i&(1<<l)))                    {                        int cost = dist[k][pos[l]];                        if(j&(1<<l)) cost += no[l].ft;                        else cost += no[l].t;                        update(dp[i|(1<<l)][j|getft[pos[l]]|(1<<l)][pos[l]],dp[i][j][k]+cost);                    }                    for(int l = 1; l <= n; l++)                        update(dp[i][j|getft[l]][l],dp[i][j][k]+dist[k][l]);                }//                for(int k = 1; k <= n; k++) if(dp[i][j][k] >= 0)//这种递推就可以只看自己点上面的景点//                {//                    for(int l = 1; l <= n; l++)//                        update(dp[i][j|getft[l]][l],dp[i][j][k]+dist[k][l]);//                }//                for(int k = 1; k <= n; k++) if(dp[i][j][k] >= 0)//                {//                    for(int l = 0; l < K; l++) if(!(i&(1<<l)))//                    {//                        if(pos[l] != k) continue;//                        int cost;//                        if(j&(1<<l)) cost = no[l].ft;//                        else cost = no[l].t;//                        update(dp[i|(1<<l)][j|getft[pos[l]]|(1<<l)][pos[l]],dp[i][j][k]+cost);//                    }//                }            }        }        printf("Case #%d: %d\n",cas++,dp[(1<<K)-1][(1<<K)-1][1]);    }    return 0;}



0 0
原创粉丝点击