HYSBZ 1497 最大权闭合图

最大获利

新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。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个中转站,建立第i个中转站的成本为Pi,有m个用户,第i个用户在中转站Ai,Bi已经建立的情况下能够带来Ci的收益,现可选择建立一些中转站来获得收益,问最大收益是多少

思路:中转站为负权,用户为正权,第i个用户向Ai,Bi两个中转站连边,这样就是求该图的最大权闭合图

最大权闭合图建图技巧:在原图的基础上增加源点 V s Vs Vs和汇点 V t Vt Vt,将原图中每条有向边替换为容量为 ∞ ∞ 的弧;增加源点 V s Vs Vs到图中每个正权顶点 i i i的弧,容量为 w i w_i wi;增加原图中每个负权顶点 j j j到汇点 V t Vt Vt的弧,容量为 − w j -w_j wj。于是,我们可以将图进行如下转换。
在这里插入图片描述
在这里插入图片描述
证明见论文: 胡伯涛《最小割模型在信息学竞赛中的应用》

#include<bits/stdc++.h>
#define MAXN 55010
#define MAXM 155010
using namespace std;
const int INF = 0x3f3f3f3f;
int head[MAXN],tot;
struct edge
{
    int v,c,nxt;
}edg[MAXM << 1];
inline void addedg(int u,int v,int c)
{
    edg[tot].v = v;
    edg[tot].c = c;
    edg[tot].nxt = head[u];
    head[u] = tot++;
}
inline void add(int u,int v,int c)
{
    addedg(u,v,c);
    addedg(v,u,0);
}
int n,m,d[MAXN];
inline bool bfs(int s,int t)
{
    queue<int> qu;
    memset(d,-1,sizeof(int)*(n+m+3));
    qu.push(s);
    d[s] = 0;
    int v;
    while(!qu.empty())
    {
        int u = qu.front();
        qu.pop();
        for(int i = head[u];i != -1;i = edg[i].nxt)
        {
            v = edg[i].v;
            if(edg[i].c > 0 && d[v] == -1)
                d[v] = d[u]+1,qu.push(v);
        }
    }
    return d[t] != -1;
}
int dfs(int u,int flow,int t)
{
    if(u == t)
        return flow;
    int res = 0;
    for(int i = head[u];i != -1;i = edg[i].nxt)
    {
        int v = edg[i].v;
        if(edg[i].c > 0 && d[v] == d[u] + 1)
        {
            int tmp = dfs(v,min(flow,edg[i].c),t);
            flow -= tmp;
            res += tmp;
            edg[i].c -= tmp;
            edg[i^1].c += tmp;
            if(flow == 0)
                break;
        }
    }
    if(res == 0)
        d[u] = -1;
    return res;
}
inline void init()
{
    memset(head,-1,sizeof(int)*(n+m+3));
    tot = 0;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        int u,v,w,s,t;
        s = 0,t = n+m+1;
        for(int i = 1;i <= n;++i)
        {
            scanf("%d",&w);
            if(w)
                add(i,t,w);
        }
        int ans = 0;
        for(int i = 1;i <= m;++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(i+n,u,INF);
            add(i+n,v,INF);
            if(w)
                add(s,i+n,w);
            ans += w;
        }
        while(bfs(s,t))
            ans -= dfs(s,INF,t);
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值