题目: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; }