题目:https://codeforces.com/gym/101908/problem/F

题意:给你n个舞台,每个舞台有很多个节目,每个节目有个开始时间,结束时间,价值,每个舞台至少出演过一个节目,所有舞台同一时刻只能一个舞台演节目,求怎么安排节目有最大价值

思路:首先舞台数只有10,而且我们必须访问每个舞台至少一次,很明显是个状态   1<<10 ,分别代表每个舞台现在演过节目没有,然后很明显我们还有有一个区间状态。

如果题目没有要求每个舞台必须演一次的话,很明显这个问题我们就可以直接按左端点排序,dp[end]=max(dp[1-begin]+val,dp[end]),我们记录下1-begin的最大值,pre,然后我们就能轻松求出来。这题多了每个舞台访问一次的要求其实是一样的道理,我们每次用pre数组更新出每个状态j的区间里面最大值

dp[i][j]   代表 前i个节目    状态j (舞台是否表演过的情况)

pre[j][k]     代表 状态j        1-k区间的最大值是多少

 

#include<bits/stdc++.h>
#define maxn 1100
#define mod 1000000007
using namespace std;
typedef long long ll;
struct sss{
    int id,val;
    int be,ed;
}a[10005];
int q[100005];
int dp[maxn][maxn];
int pre[maxn][maxn<<1];
int n,m,num,len;
int cmp(struct sss x,struct sss y){
    if(x.be==y.be) return x.ed<y.ed;
    return x.be<y.be;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&m);
        for(int j=0;j<m;j++){
            scanf("%d%d%d",&a[num].be,&a[num].ed,&a[num].val);
            q[++len]=a[num].be;
            q[++len]=a[num].ed;
            a[num++].id=i;
        }
    }
    sort(q+1,q+len+1);
    len=unique(q+1,q+len+1)-q-1;
    sort(a,a+num,cmp);
    int flag=0;
    int mx=-1;
    int dex=1;
    int M=(1<<n)-1;
    for(int i=0;i<num;i++){
        a[i].be=lower_bound(q+1,q+len+1,a[i].be)-q;
        a[i].ed=lower_bound(q+1,q+len+1,a[i].ed)-q;
        while(dex<=a[i].be){
            for(int j=1;j<=M;j++){
                pre[j][dex]=max(pre[j][dex],pre[j][dex-1]);
            }
            dex++;
        }
        int t=1<<a[i].id; 
        dp[i][t]=a[i].val;
        pre[t][a[i].ed]=max(pre[t][a[i].ed],a[i].val);
        for(int j=1;j<=M;j++){
          if(pre[j][a[i].be]) 
            dp[i][j|t]=max(dp[i][j|t],pre[j][a[i].be]+a[i].val);
        }
        for(int j=1;j<=M;j++){
          if(dp[i][j]) pre[j][a[i].ed]=max(pre[j][a[i].ed],dp[i][j]);
          }
        mx=max(mx,dp[i][M]);
    }

    if(mx==0) mx=-1;
    printf("%d",mx);
    return 0;
} 
View Code