zoukankan      html  css  js  c++  java
  • [BZOJ] 1497: [NOI2006]最大获利

    点上带权,选A则必须选B,典型的最大权闭合子图问题。

    S向正权点(用户)连容量为权值的边,负权点(中转站)向T连容量为权值相反数的边,用户向依赖的中转站连INF的边。

    求出最小割,可以这样理解。

    要不割去用户的边,代表损失这些收入,要不割去中转站的边,代表加上这些代价。

    最后用总收入(正权和)减去最小割即为所求。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    using namespace std;
     
    const int MAXN=55005;
    const int M=50005*9;
    const int INF=1<<30;
     
    inline int rd(){
        int ret=0,f=1;char c;
        while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
        while(isdigit(c))ret=ret*10+c-'0',c=getchar();
        return ret*f;
    }
     
    struct Edge{
        int next,to,f;
    }e[M<<1];
    int ecnt=1,head[MAXN];
    inline void add(int x,int y,int f){
        e[++ecnt].next = head[x];
        e[ecnt].to = y;
        e[ecnt].f = f;
        head[x] = ecnt;
    }
     
    int n,m;
    int S,T;
     
    int dep[MAXN];
    queue<int> Q;
    bool bfs(int s,int t){
        memset(dep,0,sizeof(dep));
        dep[s]=1;Q.push(s);
        while(!Q.empty()){
            int top=Q.front();Q.pop();
            for(int i=head[top];i;i=e[i].next){
                int v=e[i].to;
                if(dep[v]||!e[i].f) continue;
                dep[v]=dep[top]+1;Q.push(v);
            }
        }
        return dep[t];
    }
    int cur[MAXN];
    int dfs(int x,int flow,int t){
        if(x==t) return flow;
        int used=0,tmp;
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].to;
            if(dep[v]!=dep[x]+1) continue;
            tmp=dfs(v,min(flow-used,e[i].f),t);
            e[i].f-=tmp;e[i^1].f+=tmp;used+=tmp;
            if(used==flow) return flow;
            if(e[i].f) cur[x]=i;
        }
        if(!used) dep[x]=-1;
        return used;
    }
    int dinic(int s,int t){
        int ret=0;
        while(bfs(s,t)){
            memcpy(cur,head,sizeof(head));
            ret+=dfs(s,INF,t);
        }
        return ret;
    }
     
    int main(){
        n=rd();m=rd();
        S=n+m+1,T=n+m+2;    
        int x,y,f;
        for(int i=1;i<=n;i++){
            x=rd();add(i+m,T,x);add(T,i+m,0);
        }
        int ans=0;
        for(int i=1;i<=m;i++){
            x=rd();y=rd();f=rd();ans+=f;
            add(i,x+m,INF);add(x+m,i,0);
            add(i,y+m,INF);add(y+m,i,0);
            add(S,i,f);add(i,S,0);
        }
        ans-=dinic(S,T);
        printf("%d
    ",ans);
        return 0;
    }

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9496516.html

  • 相关阅读:
    C语言博客I作业04
    C语言I博客作业03
    C语言I博客作业02
    C语言ll作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    C语言I作业12—学期总结
    C语言I博客作业11
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9496516.html
Copyright © 2011-2022 走看看