• BZOJ_1497_[NOI2006]_最大获利_(最大流+最大权闭合图)


    描述


    http://www.lydsy.com/JudgeOnline/problem.php?id=1497

    共n个站点,给出建立每个站点所需要的花费.现在有m个客户需要开通服务,每个客户需要有两个站点,客户给钱.问最大利润是多少.

    1497: [NOI2006]最大获利

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 3932  Solved: 1926
    [Submit][Status][Discuss]

    Description

    新 的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。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公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才 能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)

    Input

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

    Output

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

    Sample Input

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

    Sample Output

    4

    HINT

    【样例说明】选择建立1、2、3号中转站,则需要投入成本6,获利为10,因此得到最大收益4。【评分方法】本题没有部分分,你的程序的输出只有和我们的答案完全一致才能获得满分,否则不得分。【数据规模和约定】 80%的数据中:N≤200,M≤1 000。 100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。

    Source

    分析


    要选一个客户,就必须要选他所需的两个站点,这样有约束关系的,可以用最大权闭合图做.

    胡伯涛的论文<最小割模型在信息学竞赛中的应用>:

    http://wenku.baidu.com/link?url=AwU_F4lYPSxxzmOrAZpL0t6lCMWjIVbuAXI59EKPbqEj7gpw0VRhhrGDU4BbOVFNGlVRt0KLZ6QrCAszJIT-TBfPV8jJ8fCTFdA4rTa3VdS

    讲得挺详细,就是看起来有点费劲...

    把客户和站点都看做点,客户是正权值,站点是负权值.要有客户就必须有站点,所以边由客户连向站点,表示如果客户被选中,他所需的两个站点也一定被选中.

    1.站点连向汇点,容量是站点的花费的绝对值;

    2.客户连向源点,容量是客户给的钱;

    3.每个客户连向他所需的两个站点,容量是INF.

    然后跑最大流即可.

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 #include<queue>
      6 #define rep(i,n) for(int i=0;i<(n);i++)
      7 #define for1(i,a,n) for(int i=(a);i<=(n);i++)
      8 #define read(a) a=getnum()
      9 #define print(a) printf("%d
    ",a)
     10 #define CC(i,a) memset(i,a,sizeof(i))
     11 using namespace std;
     12 
     13 const int maxn=5005,maxm=50005,INF=0x7fffffff;
     14 int n,m,sumw;
     15 int cost[maxn],level[maxn+maxm],iter[maxn+maxm];
     16 struct edge { int to,cap,rev; };
     17 vector <edge> g[maxn+maxm];
     18 
     19 inline int getnum()
     20 {
     21     int r=0,k=1; char c;
     22     for(c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') k=-1;
     23     for(;c>='0'&&c<='9';c=getchar()) r=r*10+c-'0';
     24     return r*k;
     25 }
     26 
     27 void add_edge(int from,int to,int cap)
     28 {
     29     g[from].push_back((edge) { to,cap,g[to].size() });
     30     g[to].push_back((edge) { from,0,g[from].size()-1 });
     31 }
     32 
     33 void bfs(int s)
     34 {
     35     CC(level,-1);
     36     level[s]=0;
     37     queue <int> q;
     38     q.push(s);
     39     while(!q.empty())
     40     {
     41         int t=q.front(); q.pop();
     42         rep(i,g[t].size())
     43         {
     44             edge e=g[t][i];
     45             if(level[e.to]<0&&e.cap>0)
     46             {
     47                 level[e.to]=level[t]+1;
     48                 q.push(e.to);
     49             }
     50         }
     51     }
     52 }
     53 
     54 int dfs(int v,int t,int f)
     55 {
     56     if(v==t) return f;
     57     for(int &i=iter[v];i<g[v].size();i++)
     58     {
     59         edge &e=g[v][i];
     60         if(e.cap>0&&level[e.to]>level[v])
     61         {
     62             int d=dfs(e.to,t,min(f,e.cap));
     63             if(d>0)
     64             {
     65                 e.cap-=d;
     66                 g[e.to][e.rev].cap+=d;
     67                 return d;
     68             }
     69         }
     70     }
     71     return 0;
     72 }
     73     
     74 int max_flow(int s,int t)
     75 {
     76     int flow=0;
     77     bfs(s);
     78     while(level[t]>0)
     79     {
     80         CC(iter,0);
     81         int f;
     82         while((f=dfs(s,t,INF))>0) flow+=f;
     83         bfs(s);
     84     }
     85     return flow;
     86 }
     87 
     88 void init()
     89 {
     90     read(n); read(m);
     91     for1(i,1,n)
     92     {
     93         read(cost[i]);
     94         add_edge(i,n+m+1,cost[i]);
     95     }
     96     for1(i,1,m)
     97     {
     98         int a,b,c;
     99         read(a); read(b); read(c);
    100         add_edge(0,n+i,c);
    101         add_edge(n+i,a,INF);
    102         add_edge(n+i,b,INF);
    103         sumw+=c;
    104     }
    105 }
    106 
    107 int main()
    108 {
    109 #ifndef ONLINE_JUDGE
    110     freopen("prof.in","r",stdin);
    111     freopen("prof.out","w",stdout);
    112 #endif
    113     init();
    114     print(sumw-max_flow(0,n+m+1));
    115     
    116 #ifndef ONLINE_JUDGE
    117     fclose(stdin);
    118     fclose(stdout);
    119     system("prof.out");
    120 #endif
    121     return 0;
    122 }
    View Code
  • 相关阅读:
    通向KDE4之路(七):文档反省器Okular和Ligature
    KDE言语绑定──KDEBindings
    KDEEdu(教诲性质软件)引见
    KDEMultimedia(KDE多媒体东西)引见
    KDESDK(KDE斥地工具)引见
    通向KDE4之路(十五):Konsole年夜整修
    企业信息化规划http://www.blogcn.com/User/fieldnet/index.html
    写在博客一周年
    Delphi 的内存操作函数(3): 给结构体指针分配内存
    在 Delphi 2009 中, for in 循环都能用在什么地方?
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5439403.html
Copyright © 2020-2023  润新知