LXVII.[USACO15JAN]Moovie Mooving G
思路1.
设\(f[i][S]\)表示在第\(i\)场(注意是场,不是部)电影时,已经看了\(S\)里面的电影是否合法。
然后贪心地取\(|S|\)最小的状态保存。光荣MLE了,\(21\%\)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,len[20],sum[20],dis[30000],id[30000];
vector<int>v[20],g[30000],res[30000];
queue<int>q;
int main(){
scanf("%d%d",&n,&m),memset(dis,0x3f3f3f3f,sizeof(dis));
for(int i=0,x,y;i<n;i++){
scanf("%d%d",&len[i],&x),sum[i+1]=sum[i]+x;
for(int j=0;j<x;j++)scanf("%d",&y),v[i].push_back(y),id[sum[i]+j]=i;
}
// for(int i=0;i<=n;i++)printf("%d ",sum[i]);puts("");
id[sum[n]]=n;
for(int i=0;i<n;i++)for(int k=0;k<v[i].size();k++){
int x=v[i][k];
if(!x)q.push(sum[i]+k),dis[sum[i]+k]=0,res[sum[i]+k].push_back(1<<i);
int ed=x+len[i];
if(ed>=m){g[sum[i]+k].push_back(sum[n]);continue;}
for(int j=0;j<n;j++){
if(i==j)continue;
vector<int>::iterator it=upper_bound(v[j].begin(),v[j].end(),ed);
if(it==v[j].begin())continue;
it--;
if(*it+len[j]<ed)continue;
g[sum[i]+k].push_back(sum[j]+it-v[j].begin());
}
}
// for(int i=0;i<n;i++){for(int j=0;j<v[i].size();j++){printf("%d:",sum[i]+j);for(auto x:g[sum[i]+j])printf("%d ",x);puts("");}puts("");}
// for(int i=0;i<=sum[n];i++)printf("%d ",id[i]);puts("");
while(!q.empty()){
int x=q.front();q.pop();
// printf("%d:\n",x);
for(auto y:g[x]){
if(dis[y]<=dis[x])continue;
// printf("%d\n",y);
for(auto i:res[x])if(!(i&(1<<id[y]))){
if(dis[y]!=dis[x]+1)dis[y]=dis[x]+1,res[y].clear();
break;
}
if(dis[y]!=dis[x]+1)continue;
for(auto i:res[x])if(!(i&(1<<id[y])))res[y].push_back(i|(1<<id[y]));
q.push(y);
}
}
printf("%d\n",dis[sum[n]]==0x3f3f3f3f?-1:dis[sum[n]]);
return 0;
}
思路2.
发现当一场电影结束后,无论这一场是在哪里看的都没关系。
因此我们设\(f[S]\)表示只看集合\(S\)里面的电影,最多能够看多久。
转移就枚举下一场看什么,二分一下小于等于\(f[S]\)的第一场比赛并观看即可。
复杂度\(O(n2^n\log C)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,f[1<<20],len[20],res=0x3f3f3f3f;
vector<int>v[20];
int main(){
scanf("%d%d",&n,&m);
for(int i=0,x,y;i<n;i++){
scanf("%d%d",&len[i],&x);
while(x--)scanf("%d",&y),v[i].push_back(y);
}
for(int x=0;x<(1<<n);x++){
if(f[x]>=m){res=min(res,__builtin_popcount(x));continue;}
for(int i=0;i<n;i++){
if(x&(1<<i))continue;
vector<int>::iterator it=upper_bound(v[i].begin(),v[i].end(),f[x]);
if(it==v[i].begin())continue;
it--;
f[x|(1<<i)]=max(f[x|(1<<i)],*it+len[i]);
}
}
printf("%d\n",res==0x3f3f3f3f?-1:res);
return 0;
}