1. 程式人生 > >Gym 101908F Music Festival 狀壓dp 離散優化

Gym 101908F Music Festival 狀壓dp 離散優化

題目連結: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;
}