标签:ati out 开始时间 als efi nbsp oid other better
题目大意:
给出n,每天有n个小时。有m种电影,每个电影有开始时间和结束时间,和01两种种类,k个人,每一部电影只能被一个人看,会获得一个快乐值wi,如果一个人连续看两部相同种类的电影,快乐值会消耗W,(先加上wi,再减去W)。如果两部电影的开始时间和结束时间是重合的,则可以连续看。题目保证所有的wi都大于等于W。
思路:
拆点,将每一部电影拆成 i 和 i+m 两个点,建立一条费用为 -wi,流量为1的边,如果两部电影可以连着看,则建边,同种类的费用为W,不同种类的费用为0,建立一个源点连向所有电影,一个汇点也连接所有电影,一个超级源点,流量为k,连着源点。然后跑最小费用最大流,答案取负就可以了。
为什么这样就可以呢,因为题目保证了所有wi都大于W,也就是说,一部电影带来的收益肯定是正的,如果这个收益取负,那么我们就要最小的收益,而尽可能多的人就可以看尽可能多的电影,所以流量就要尽量大,这样就满足费用流的性质,然后就是建边稍微注意下,模板套一套就可以了。
#include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=410; struct edge{ int v,f,w,Next; edge(){} edge(int a,int b,int c,int d){v = a,f=b,w=c,Next=d;} }e[maxn*maxn]; int pree[maxn*2],prevv[maxn*2]; struct node{ int beg,en,val,op; }video[maxn]; int tot=1,head[maxn*2],src,sink,dist[maxn*2]; bool inque[maxn*2]; inline void addv(int u,int v,int c,int w){ e[++tot]={v,c,w,head[u]}; head[u]=tot; e[++tot]={u,0,-w,head[v]}; head[v]=tot;; } inline void init(){ CLR(pree,0); CLR(prevv,0); tot=1,CLR(head,0); } int n,m,k,W; inline bool findpath(){ queue<int >q; q.push(src); //printf("src:%d\n",src); CLR(dist,inf); CLR(inque,0); dist[src]=0; inque[src]=1; while(!q.empty()) { int u=q.front(); q.pop(); inque[u]=0; for(int i=head[u]; i ;i=e[i].Next) { if(e[i].f >0 && dist[u]+e[i].w < dist[e[i].v]){ dist[e[i].v]=dist[u]+e[i].w; prevv[e[i].v]=u; pree[e[i].v]=i; if(!inque[e[i].v]){ inque[e[i].v]=1; q.push(e[i].v); } } } // printf("%d\n",u); } if(dist[sink]<inf)return true; return false; } inline int augment(){ int u=sink; int delta = inf ; while(u!=src) { // printf("%d\n",u); if(e[pree[u]].f<delta)delta = e[pree[u]].f; u = prevv[u]; } u= sink; while(u!=src){ e[pree[u]].f -= delta; e[pree[u] ^ 1].f +=delta; u = prevv[u]; } return dist[sink]*delta; } inline int mincostflow(){ int cur=0,ans=0; while(findpath()){ cur += augment(); if(cur<ans)ans=cur; } return ans; } int main(){ int T; cin>>T; while(T--) { init(); scanf("%d%d%d%d",&n,&m,&k,&W); src=2*m+1,sink=2*m+3; for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&video[i].beg,&video[i].en,&video[i].val,&video[i].op); } for(int i=1;i<=m;i++){ addv(i,i+m,1,-video[i].val); addv(src,i,1,0); addv(i+m,sink,1,0); for(int j=1;j<=m;j++) { if(i==j)continue; if(video[i].en<=video[j].beg){ if(video[i].op!=video[j].op) { addv(i+m,j,1,0); } else { addv(i+m,j,1,W); } } } } src++; addv(src,src-1,k,0); printf("%d\n",-mincostflow()); } }
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 957 Accepted Submission(s): 474
标签:ati out 开始时间 als efi nbsp oid other better
原文地址:https://www.cnblogs.com/mountaink/p/9813897.html