Gym 101908F Music Festival 状压dp 离散优化

版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/83543929

题目链接:http://codeforces.com/gym/101908/problem/F

题意:

       给你n个场景,每个场景有ki场舞台剧,每一场舞台剧都有一个开始时间si,结束时间ei,和一个获得的开心值gi。一场舞台剧如果开始看了就要一直看到结束,如果这一场刚结束可以马上开始看另一个场景的另一场舞台剧(即点交集也还可以看),现在要你计算,如果每一个场景都至少要看一场舞台剧,则能获得的最大开心值是多少,如果不能做到就输出-1.

做法:

       很明显我们看到场景数量最多只有10,那么很明显就要用状压dp来做了,01分别表示这个场景是否被取到过,dp开的两维表示,以时间i为终点的时候,在状态j的情况下能获得的最大开心值。然后最关键的来了,要先for时间,在每次进行状态转移前把前一个时间的该状态最大值保存到这个状态。同时还可以对时间进行离散化,把时间压缩到4000,其实本来的86400也是可以做的。然后就是dp啦。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[5000][(1<<10)+2],n;
struct node{
    ll id,st,en,gain;
}e[1005];
vector<node> ve[5000];
ll tmp[10005],ntmp;
int main(){
    int now=0,num;
    scanf("%lld",&n);
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<n;i++){
        scanf("%d",&num);
        for(int j=0;j<num;j++){
            ++now;
            scanf("%lld%lld%lld",&e[now].st,&e[now].en,&e[now].gain);
            e[now].id=i;
            tmp[++ntmp]=e[now].st,tmp[++ntmp]=e[now].en;
        }
    }
    sort(tmp+1,tmp+1+ntmp);
    ntmp=unique(tmp+1,tmp+1+ntmp)-tmp-1;
    for(int i=1;i<=now;i++){
        e[i].st=lower_bound(tmp+1,tmp+1+ntmp,e[i].st)-tmp;
        e[i].en=lower_bound(tmp+1,tmp+1+ntmp,e[i].en)-tmp;
        ve[e[i].st].push_back(node{e[i].id,e[i].st,e[i].en,e[i].gain});
    }
    dp[0][0]=0;
    for(int i=0;i<=ntmp;i++){
        for(int k=0;k<(1<<n);k++)
            dp[i+1][k]=max(dp[i][k],dp[i+1][k]);
        for(int j=0;j<ve[i].size();j++){
            for(int k=0;k<(1<<n);k++){
                node t=ve[i][j];
                if(dp[i][k]==-1) continue;
                dp[t.en][k|(1<<t.id)]=max(dp[t.en][k|(1<<t.id)],dp[i][k]+t.gain);
            }
        }
    }
    printf("%lld\n",dp[ntmp][(1<<n)-1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/83543929