zoukankan      html  css  js  c++  java
  • 【BZOJ1497】【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≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100

    本来想看妹主席的ppt补一波最小割,然后照着ppt上的套路建图,然后连样例都过不了……
    然后自己脑补啊,然后脑补出来的图离妹主席的模型越来越远了,最后想到一种建图好像有理有据的样子

    测一下样例过了,然后抱着直接WA掉的心态裸交1A……

    具体就是先使用最小不能获得的收益转化成最小割模型

    然后s到i表示选,i到t表示不选,那么如果把s->i割掉就会损失pi的收益(表示选),把i->t割掉就会损失wi/2的收益(表示不选)

    为啥是wi/2?

    因为如果a和b有两个都选则获得wi的收益的条件,就会在ab之间连两个方向相反流量为wi/2的边(为啥不是无向边?,因为网络流要建反向边)

    然后如果两个都没选那么割掉两个i->t就是少了wi/2*2的收益,如果一个选一个没选那么没选的a就会通过s->a,a->b,b->t割一个wi/2的边,依旧会少wi/2*2的收益

    只有当两个都选即s->a,s->b都被割掉的时候a,b之间的边和a,b到t的边才能避免被割掉,获得wi/2*2的收益

    (感觉妹主席的方法和我的核心思想是一样的但是在某些细节上不同?反正我A掉了

    恩差不多就是酱紫

    为了防止精度问题我输入的时候乘个2输出的时候再除回去,不知道这样是否有必要

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 const int oo=168430090;
     8 int rd(){int z=0,mk=1;  char ch=getchar();
     9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
    10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    11     return z*mk;
    12 }
    13 struct ddd{int nxt,y,v,rvs;}e[410000];  int lk[5100],ltp=0;
    14 inline void ist(int x,int y,int z){  
    15     e[++ltp].nxt=lk[x],lk[x]=ltp,e[ltp].y=y,e[ltp].v=z,e[ltp].rvs=ltp+1;
    16     e[++ltp].nxt=lk[y],lk[y]=ltp,e[ltp].y=x,e[ltp].v=0,e[ltp].rvs=ltp-1;
    17 }
    18 int n,m,a[5100];  int s,t,M=100;
    19 int lvl[5100];
    20 int q[5100],hd=0;
    21 int quq=0;
    22 bool gtlvl(){
    23     memset(lvl,0,sizeof(lvl));
    24     q[hd=1]=s,lvl[s]=1;
    25     for(int k=1;k<=hd;++k)
    26         for(int i=lk[q[k]];i;i=e[i].nxt)if(e[i].v && !lvl[e[i].y])
    27             lvl[e[i].y]=lvl[q[k]]+1,q[++hd]=e[i].y;
    28     return lvl[t];
    29 }
    30 int mxflw(int x,int y){
    31     if(x==t)  return y;
    32     int bwl=0,flw=0;
    33     for(int i=lk[x];i && bwl<y;i=e[i].nxt)if(e[i].v && lvl[e[i].y]==lvl[x]+1)
    34         if((flw=mxflw(e[i].y,min(y-bwl,e[i].v)))){
    35             bwl+=flw;
    36             e[i].v-=flw,e[e[i].rvs].v+=flw;
    37             //cout<<x<<"->"<<e[i].y<<" "<<flw<<endl;
    38         }
    39     if(!bwl)  lvl[x]=0;
    40     return bwl;
    41 }
    42 int dnc(){
    43     int bwl=0,flw;
    44     while(gtlvl())while(flw=mxflw(s,oo))  bwl+=flw;
    45     return bwl;
    46 }
    47 int main(){//freopen("ddd.in","r",stdin);
    48     cin>>n>>m;  s=0,t=n+1;
    49     for(int i=1;i<=n;++i)  ist(s,i,rd()*2);
    50     int l,r,v;
    51     for(int i=1;i<=m;++i){
    52         l=rd(),r=rd(),v=rd()*2;  quq+=v,v>>=1;
    53         a[l]+=v,a[r]+=v,ist(l,r,v),ist(r,l,v);
    54     }
    55     for(int i=1;i<=n;++i)  ist(i,t,a[i]);
    56     cout<<(quq-dnc())/2<<endl;
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    Assert.isTrue 用法
    P2967 [USACO09DEC]视频游戏的麻烦Video Game Troubles
    最近目标2333
    LibreOJ β Round #2」贪心只能过样例
    CF1062F Upgrading Cities 拓扑排序
    CF1108F MST Unification
    CF915D Almost Acyclic Graph 拓扑排序
    Swift日历控件Calendar
    README.md的markdown语法
    MAC打开App显示已损坏
  • 原文地址:https://www.cnblogs.com/JSL2018/p/6541374.html
Copyright © 2011-2022 走看看