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

题目链接:点击打开链接

题意:给你一个n个点的完全图, 图中任意两个点都有直接相连的路,在某些点上可以获得某些景观的入场券,有入场券和没有入场券进入景观要等候的时间不同,有k个景观,要求从1点出发参观完所有景观后回到1的最小花费。

思路: 很明显的状态压缩DP, 因为 k 很小,所以可以压缩成一个整数,表示哪些景观已经参观完了。 然后还要表示出当前到了哪个点, 又因为有没有票的等候时间是不同的,所以再压缩一维表示当前有了哪些景观的票。  所以用d[i][s1][s2]表示当前在i点,已经参观了s1表示的景观,有s2表示的票  的最小花费。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int mod = 1000000000 + 7;
const int INF = 1000000000;
const int maxn = 55;
const int maxk = 8;
int T,n,m,k,kase=0,dist[maxn][maxn],d[maxn][1<<maxk][1<<maxk];
int u,v,c,piao[maxn],vis[maxn][1<<maxk][1<<maxk];
struct node {
    int p, t, ft, ni;
}a[maxk];
void floyd() {
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            for(int k=1;k<=n;k++) {
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
            }
        }
    }
}
int dp(int u, int S, int s) {
    int& ans = d[u][S][s];
    if(u == 1 && S == ((1<<k)-1)) return 0;
    if(vis[u][S][s] == kase) return ans;
    vis[u][S][s] = kase;
    ans = INF;
    for(int i=0;i<k;i++) {
        if(S & (1<<i)) continue;
        if(s & (1<<i)) {
            ans = min(ans, dp(a[i].p, S|(1<<i), s|piao[a[i].p]) + a[i].ft + dist[u][a[i].p]);
        }
        else ans = min(ans, dp(a[i].p, S|(1<<i), s|piao[a[i].p]) + a[i].t + dist[u][a[i].p]);
    }
    for(int i=1;i<=n;i++) {
        ans = min(ans, dp(i, S, s|piao[i])+dist[u][i]);
    }

    return ans;
}
int main() {
    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++) {
                if(i == j) dist[i][j] = 0;
                else dist[i][j] = INF;
            }
        }
        for(int i=0;i<m;i++) {
            scanf("%d%d%d",&u,&v,&c);
            dist[u][v] = dist[v][u] = c;
        }
        floyd();
        ++kase;
        memset(piao, 0, sizeof(piao));
        int S = 0, s = 0;
        for(int i=0;i<k;i++) {
            scanf("%d%d%d%d",&a[i].p,&a[i].t,&a[i].ft,&a[i].ni);
            for(int j=0;j<a[i].ni;j++) {
                scanf("%d",&v);
                piao[v] |= (1<<i);
                if(v == 1) s |= (1<<i);
            }
        }
        printf("Case #%d: ",kase);
        printf("%d\n",dp(1, 0, s));
    }
    return 0;
}


你可能感兴趣的:(HDU,状态压缩dp,ACM-ICPC)