[JZOJ2224] 【NOI2006】最大获利

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公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)

【数据规模和约定】
  80%的数据中:N≤200,M≤1 000。
  100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。

Solution

想必这道题人人都知道,最大权闭合图的模板题~

每个用户群和每个基站建议点,用户群向依赖的基站连边,显然最大权闭合图是答案

最大权闭合图?看这里

P.S.:这题要用 Dinic ,用 GAP 会被卡

Code

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define LL long long
#define N 60000
#define M 500000
#define INF 2000000000
using namespace std;
int n,m,nt[M],lt[M],fs[M],dt[M],zs[M],f[M],st,ed,m1,h[N],d[M];
void fx()
{
    zs[m1]=m1-1;
    zs[m1-1]=m1;
}
void link(int x,int y,int z)
{
    d[++m1]=y;
    f[m1]=z;
    if (fs[x]==0) fs[x]=m1;
    lt[x]=nt[lt[x]]=m1;
}
void mt(int x,int y,int z)
{
    link(x,y,z);
    link(y,x,0);
    fx();
}
bool bfs()
{
    memset(h,0,sizeof(h));
    int i=0,j=1,k,p,l;
    dt[j]=st;
    h[st]=1;
    while (i<j)
    {
        k=dt[++i];
        for(l=fs[k];l>0;l=nt[l])
        {
            p=d[l];
            if (f[l]>0&&h[p]==0) dt[++j]=p,h[p]=h[k]+1; 
        }
    }
    return h[ed]>0;
}
int dinic(int k,int s)
{
    int i,p,l=0,sl=0;
    if(k==ed) return s;
    for(i=fs[k];i>0;i=nt[i])
    {
        p=d[i];
        if (f[i]>0&&h[p]==h[k]+1)
        {
            l=dinic(p,min(s,f[i]));
            if (l>0)
            {
                sl+=l;
                s-=l;
                f[i]-=l;
                f[zs[i]]+=l;
                if (s==0) break;
            }
        }
    }
    if (sl==0) h[k]=-1;
    return sl;
}
int main()
{
    cin>>n>>m;
    st=n+m+1;
    ed=n+m+2;
    m1=0;
    int i;
    fo(i,1,n) 
    {
        int p;
        scanf("%d",&p);
        mt(m+i,ed,p);
    }
    int s=0;
    fo(i,1,m)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        s+=z;
        mt(st,i,z);
        mt(i,x+m,INF);
        mt(i,y+m,INF);
    }
    while (bfs()) 
        s-=dinic(st,INF);
    cout<<s;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值