• 2011东北地区赛E题(最大费用最大流/二分图最大权匹配)


    题意:过年,一家人做家务,每个人做完每样家务会获得快乐值,每个人最多做家务的数量给予限制,求全家人的最大快乐值.

    构图:费用流.源点向家庭成员连容量为家务数量的限制数,费用为0的边,家务向终点连容量为1,费用为0的边,家庭成员向家务连容量为1,费用为-权值的边,

    求最小费用最大流,取反.

    View Code
    #include <iostream>
    #include <stdio.h>
    #include <queue>
    #include <math.h>
    #include <string.h>
    using namespace std;
    #define V 5500
    #define E 5007000
    #define inf 0x3F3F3F3F
    int n,m;
    int vis[V];
    int dist[V];
    int pre[V];
    
    struct Edge{
        int u,v,c,cost,next;
    }edge[E];
    int head[V],cnt;
    void init(){
        cnt=0;
        memset(head,-1,sizeof(head));
    }
    
    void addedge(int u,int v,int c,int cost){
        edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost;
    
        edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;
    
        edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost;
        edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++;
    }
    
    bool spfa(int begin,int end){
        int u,v;
        queue<int> q;
    
        for(int i=0;i<=end+2;i++){
            pre[i]=-1;
            vis[i]=0;
            dist[i]=inf;
        }
        vis[begin]=1;
        dist[begin]=0;
        q.push(begin);
    
        while(!q.empty()){
    
            u=q.front();
            q.pop();
            vis[u]=0;
    
            for(int i=head[u];i!=-1;i=edge[i].next){
                if(edge[i].c>0){
                    v=edge[i].v;
                    if(dist[v]>dist[u]+edge[i].cost){
                        dist[v]=dist[u]+edge[i].cost;
                        pre[v]=i;
                        if(!vis[v]){
                            vis[v]=true;
                            q.push(v);
                        }
                    }
                }
            }
    
        }
    
        return dist[end]!=inf;
    }
    
    int MCMF(int begin,int end){
        int ans=0,flow;
        int flow_sum=0;
    
        while(spfa(begin,end)){
    
            flow=inf;
            for(int i=pre[end];i!=-1;i=pre[edge[i].u])
                if(edge[i].c<flow)
                    flow=edge[i].c;
            for(int i=pre[end];i!=-1;i=pre[edge[i].u]){
                edge[i].c-=flow;
                edge[i^1].c+=flow;
            }
            ans+=dist[end];
            flow_sum+=flow;
    
        }
        return ans;
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        int gain[50][30];
        int afford[50];
        while(cin >> n >> m){
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    cin >> gain[i][j];
            for(int i=1;i<=n;i++)
                cin >> afford[i];
            init();
            for(int i=1;i<=n;i++)
                addedge(0,i,afford[i],0);
            for(int i=n+1;i<=n+m;i++)
                addedge(i,n+m+1,1,0);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    addedge(i,n+j,1,-gain[i][j]);
            int res=MCMF(0,n+m+1);
            printf("%d\n",-res);
        }
    
        return 0;
    }
  • 相关阅读:
    hystrix熔断器之HystrixRequestLog
    RXJAVA之聚合操作
    RXJAVA之变换操作
    RXJAVA之创建被观察者
    小程序学习
    redis的使用
    Stream/Bytes[]/Image对象相互转化
    消息队列转载
    业务层使用事务
    ViewState 和字段属性的差异
  • 原文地址:https://www.cnblogs.com/markliu/p/2532996.html
Copyright © 2020-2023  润新知