zoukankan      html  css  js  c++  java
  • HDU 6437 Problem L.Videos (最大费用)【费用流】

    <题目链接>

    题目大意:

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

    解题分析:

    本题用费用流求解的方式还是比较直观的。因为本题要求的是最大费用,所以我们需要建图的时候需要将所有实际费用取反,然后将最后最小费用最大流求出的答案取反,就是要求的最大费用。具体建图过程见代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define clr(a,b) memset(a,b,sizeof(a))
    template<typename T>
    inline void read(T&x){
        x=0;int f=1;char c=getchar();
        while(c<'0' || c>'9'){ if(c=='-')f=-1;c=getchar(); }
        while(c>='0' && c<='9'){ x=x*10+c-'0';c=getchar(); }
        x*=f;
    }
    
    //最小费用最大流模板
    struct MCMF{
        static const int N = 5e4+100, M = 5e5+5, INF = 0x7fffffff; 
    
        int n, m, head[N], s, t, cnt;
        int dist[N], inq[N], pre[N], incf[N];
        int mxflow, mncost;
        struct Edge{ int to, cap, cost, next; } edge[M * 4];
    
        inline void init(int l, int r, int ss, int tt){
            //for(int i = l; i <= r; i++ ){head[i] = -1;}
            memset(head, -1, sizeof(head));
            s = ss, t = tt, cnt = 1;
            mxflow = mncost = 0;
        }
        inline void add(int u,int v,int cap,int cost){
            edge[++cnt]=(Edge){v,cap,cost,head[u]};head[u]=cnt;
            edge[++cnt]=(Edge){u,0,-cost,head[v]};head[v]=cnt;
        }
    
        bool spfa(int s, int t){       //slf优化的spfa(双端队列优化)
            for(int i = 0; i < N; i++)
                dist[i] = INF, inq[i] = 0;
            clr(pre,0);
            deque<int>q;
            inq[s]=1,dist[s] = 0;
            q.push_back(s);
            incf[s] = INF;
            while(!q.empty()){     
                int u = q.front();q.pop_front();
                inq[u] = 0;
                for(int i=head[u];~i;i=edge[i].next){
                    int v=edge[i].to,cap=edge[i].cap,cost=edge[i].cost;
                    if(cap>0 && dist[v]>dist[u]+cost){     //更新每个点的最小费用
                        dist[v]=dist[u]+cost;
                        incf[v]=min(incf[u], cap);     //得到v点所在路径上的最小容量
                        pre[v]=i;     //记录下这个点的前驱正向边
                        if(!inq[v]){
                            inq[v]=1;
                            if(q.empty() || dist[v]>dist[q.front()])q.push_back(v);
                            else q.push_front(v);       //如果最小费用小于等于队首,直接塞入队列首
                        }
                    }
                }
            }
            return dist[t]!=INF;
        }
        void update(int s,int t){
            int x=t;
            while(x!=s){
                int pos=pre[x];
                edge[pos].cap-=incf[t];      
                edge[pos^1].cap+=incf[t];
                x=edge[pos^1].to;
            }
            mxflow+=incf[t];
            mncost+=dist[t]*incf[t];
        }
        void minCostMaxFlow(int s,int t){
            while(spfa(s,t))
                update(s,t);
        }
    }mcmf;
    
    const int NN = 500 + 7;
    struct Node{ int l, r, w, fp; } node[NN];
    
    int st,ed;
    inline void GetMap(){
        int n,m,k,w;
        read(n);read(m);read(k);read(w);
        st=0,ed=2*m+2;       //0代表源点,2*m+1代表慈元典,ed代表汇点
        mcmf.init(st,ed,st,ed);
        mcmf.add(st,2*m+1,k,0);      //源点向次源点连一条容量为k,费用为0的边
        for(int i=1;i<=m;i++)
            scanf("%d%d%d%d",&node[i].l,&node[i].r,&node[i].w,&node[i].fp);
        for(int i=1;i<=m;i++){
            for(int j=1;j<=m;j++){
                if(i==j)continue;
                if(node[i].r<=node[j].l)     //对于那些满足条件的video, i的出点向j的入点连一条容量为1,费用为0(或者如果这两个点类型相同的话,费用就为W,因为本题是将所有费用置为它的相反数了)
                    mcmf.add(i+m,j,1,(node[i].fp==node[j].fp)?w:0);      //因为本题是求最大费用,所以要将所有费用取反,这里就是 w 
            }
        }
        for(int i=1;i<=m;i++)
            mcmf.add(i,i+m,1,-node[i].w);   //拆点,所有点的入点向入点连一条容量为1,费用为node[i].w的边
        for(int i=1;i<=m;i++)
            mcmf.add(2*m+1,i,1,0);     //源点向所有的点连上一条容量为1,费用为0的边
        for(int i=1;i<=m;i++)
            mcmf.add(i+m,ed,1,0);      //所有点的出度连一条容量为1,费用为0的边
    }
    inline void Solve(){
        mcmf.minCostMaxFlow(st,ed);
        printf("%d
    ",-mcmf.mncost);     //取相反数,就是实际意义上的最大费用
    }
    int main(){
        int T;cin>>T;
        while(T--){
            GetMap();
            Solve();
        }
    }
  • 相关阅读:
    Mybatis 原始dao CRUD方法
    JQuery的焦点事件focus() 与按键事件keydown() 及js判断当前页面是否为顶级页面 子页面刷新将顶级页面刷新 window.top.location
    使用actionerror做失败登录验证
    Java项目中的下载 与 上传
    shiro框架 4种授权方式 说明
    javascript 中数组的创建 添加 与将数组转换成字符串 页面三种提交请求的方式
    序列化表单为json对象,datagrid带额外参提交一次查询 后台用Spring data JPA 实现带条件的分页查询 多表关联查询
    Spring data JPA 理解(默认查询 自定义查询 分页查询)及no session 三种处理方法
    orcal 数据库 maven架构 ssh框架 的全注解环境模版 maven中央仓库批量删除lastupdated文件后依然是lastupdated解决方法 mirror aliyun中央仓库
    EasyUI加zTree使用解析 easyui修改操作的表单回显方法 验证框提交表单前验证 datagrid的load方法
  • 原文地址:https://www.cnblogs.com/00isok/p/10705047.html
Copyright © 2011-2022 走看看