zoukankan      html  css  js  c++  java
  • 【JZOJ2224】【NOI2006】最大获利

    题目描述

      新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最优化等项目。
      在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。
      另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N)
      THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)

    输入

    输入文件中第一行有两个正整数N和M 。
    第二行中有N个整数描述每一个通讯中转站的建立成本,依次为P1, P2, …, PN 。
    以下M行,第(i + 2)行的三个数Ai, Bi和Ci描述第i个用户群的信息。
    所有变量的含义可以参见题目描述。

    输出

    你的程序只要向输出文件输出一个整数,表示公司可以得到的最大净获利。

    样例输入

    5 5
    1 2 3 4 5
    1 2 3
    2 3 4
    1 3 3
    1 4 2
    4 5 3

    样例输出

    4

    数据范围

    80%的数据中:N≤200,M≤1 000。
    100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。

    样例解释

    选择建立1、2、3号中转站,则需要投入成本6,获利为10,因此得到最大收益4。

    解法

    网络流建模——最大权闭合子图:
    把一个用户群视为一个权值为ci的点,每个中转站视为一个权值为-pi的点。
    每个代表用户群的点向代表ai和bi的中转站的点连一条有向边。
    那么就是求原图的最大权闭合子图。


    建模:
    源点向所有权值为正的点连一条容量为其权值的边;
    所有权值为负的点向汇点连一条容量为其权值的绝对值的边;
    原图中有的边照搬并具有无穷大容量。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    #define sqr(x) ((x)*(x))
    #define ln(x,y) int(log(x)/log(y))
    #define lab(x) x+m+1
    #define user(x) x+1
    using namespace std;
    const char* fin="ex2224.in";
    const char* fout="ex2224.out";
    const int inf=0x7fffffff;
    const int maxn=60007,maxm=maxn*10;
    int n,m,i,j,k,l,tot=1,num,sum,ans;
    int fi[maxn],la[maxm],ne[maxm],va[maxm];
    int bz[maxn],cnt[maxm];
    void add_line(int a,int b,int c){
        tot++;
        ne[tot]=fi[a];
        la[tot]=b;
        va[tot]=c;
        fi[a]=tot;
    }
    void add(int v,int u,int r){
        add_line(v,u,r);
        add_line(u,v,0);
    }
    int gap(int v,int flow){
        int i,use=0,k;
        if (v==num) return flow;
        for (k=fi[v];k;k=ne[k])
            if (va[k] && bz[v]==bz[la[k]]+1){
                i=gap(la[k],min(flow-use,va[k]));
                use+=i;
                va[k]-=i;
                va[k^1]+=i;
                if (use==flow || bz[1]==num) return use;
            }
        if (!--cnt[bz[v]]) bz[1]=num;
        cnt[++bz[v]]++;
        return use;
    }
    int main(){
        scanf("%d%d",&n,&m);
        num=n+m+2;
        for (i=1;i<=n;i++){
            scanf("%d",&j);
            add(lab(i),num,j);
        }
        for (i=1;i<=m;i++){
            scanf("%d%d%d",&j,&k,&l);
            add(1,user(i),l);
            add(user(i),lab(j),inf);
            add(user(i),lab(k),inf);
            sum+=l;
        }
        cnt[0]=num;
        while (bz[1]<num) ans+=gap(1,inf);
        ans=sum-ans;
        printf("%d",ans);
        return 0;
    }

    启发

    存在依赖关系的点,即有最大权闭合子图;
    譬如选择一个点,必须选他的后继之类的。

  • 相关阅读:
    poj 2676 Suduku (dfs)
    poj 1562 Oil Deposits (dfs)
    poj 2907 Collecting Beepers (dfs)
    poj 1655 Balancing Act (树形dfs)
    poj 3411 Paid Roads (dfs)
    hdu 2896 病毒侵袭 (AC)
    hdu 3065 病毒侵袭持续中 (AC)
    poj 2251 Dungeon Master (bfs)
    java中debug使用
    Swing入门级小项目总结
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714866.html
Copyright © 2011-2022 走看看