• 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();
        }
    }
  • 相关阅读:
    在新浪爱问上看到的有趣名字都记下来
    FastReports_4.14.1 _Cliff手动安装
    计算机算法对做事效率的启发(既要高强度猛攻,也要细水长流)
    有趣的数组
    listView 分页加载数据
    如何隐藏Cognos Viewer
    使用DBUnit实现对数据库的测试
    通过Jasmine和Guard自动测试JavaScript
    for惠普2013实习生
    栈的顺序存储,所谓的顺序栈
  • 原文地址:https://www.cnblogs.com/00isok/p/10705047.html
Copyright © 2020-2023  润新知