Problem L.Videos(费用流)

原题: http://acm.hdu.edu.cn/showproblem.php?pid=6437

题意:

一天有N个小时,有m个节目(每种节目都有类型),有k个人,连续看相同类型的节目会扣w快乐值。
每一种节目有都一个播放区间[l,r]。每个人同一时间只能看一个节目,看完可以获得快乐值。问最多可以获得多少快乐?

解析:

乍一看是dp题,但是k个人不好维护。

最小费用最大流可以做,将快乐值的相反数作为费用,流量为人数。因为如果人多的话就不需要两个人连续挤一段了,所以答案流量一定会达到最值。

建图:

  1. 超级源点到源点流K(只能有k条路线)
  2. 源点到各个点(时间段)流1
  3. 点到其拆点流1,花费-w[i]
  4. 各拆点到汇点流1
  5. 可以连接的点(i->j),i的拆点到j流1,如果连续且种类相同,花费W在这里插入图片描述
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define LL long long
#define pill pair<int,int>

const int inf=0x3f3f3f3f;
const LL infll=1e18;
const int N=1010,M=202020;

int head[N],nex[M],to[M],val[M],cost[M],now;
void add(int a,int b,int v,int c){
    to[++now]=b;val[now]=v;cost[now]=c;nex[now]=head[a];head[a]=now;
    to[++now]=a;val[now]=0;cost[now]=-c;nex[now]=head[b];head[b]=now;
}

//*********************

int sp,ep,dis[N];

bool vis[N];
int pre[N];

bool SPFA(int &flow,int &cos){
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    for(int i=0;i<N;i++)dis[i]=inf;

    queue<int>Q;
    dis[sp]=0;vis[sp]=1;Q.push(sp);
    int d=inf;
    while(!Q.empty()){
        int p=Q.front();Q.pop();
        vis[p]=0;
        for(int i=head[p];~i;i=nex[i]){
            int u=to[i];
            if(val[i]>0&&dis[u]-cost[i]>dis[p]){
                dis[u]=dis[p]+cost[i];
                pre[u]=i;
                if(!vis[u]){
                    vis[u]=1;Q.push(u);
                }
            }
        }
    }
    if(dis[ep]==inf)return 0;
    for(int i=pre[ep];~i;i=pre[to[i^1]]){
        d=min(d,val[i]);
    }
    for(int i=pre[ep];~i;i=pre[to[i^1]]){
        val[i]-=d;
        val[i^1]+=d;
        cos+=cost[i]*d;
    }
    flow+=d;
    return 1;
}

int MinCost(){
    int flow=0,cost=0;
    while(SPFA(flow,cost)){}
    return cost;
}

//***********************

int n,m,k,W;
struct node{
    int id,s,t,v,op;
    bool operator < (const node &r)const{
        return s<r.s;
    }
}e[201];

void init(){
    now=-1;//要求第一条边为0
    memset(head,-1,sizeof(head));
}

//sp -p-> point --> ep
int main(){int t;scanf("%d",&t);while(t--){
    scanf("%d%d%d%d",&n,&m,&k,&W);
    init();
    sp=0;ep=N-1;
    int tmp_sp=N-2;
    add(sp,tmp_sp,k,0);
    for(int i=1;i<=m;i++){
        e[i].id=i;
        scanf("%d%d%d%d",&e[i].s,&e[i].t,&e[i].v,&e[i].op);
        add(tmp_sp,i,1,0);
        add(m+i,ep,1,0);
        add(i,m+i,1,-e[i].v);
    }
    sort(e+1,e+1+m);
    for(int i=1;i<m;i++){
        for(int j=i+1;j<=m;j++){
            if(e[i].t<=e[j].s){
                if(e[i].op!=e[j].op){
                    add(e[i].id+m,e[j].id,1,0);
                }
                else{
                    add(e[i].id+m,e[j].id,1,W);
                }
            }
        }
    }
    int ans=MinCost();
    printf("%d\n",-ans);
}}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/86621637
今日推荐