最大获利
新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。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两个中转站连边,这样就是求该图的最大权闭合图
最大权闭合图建图技巧:在原图的基础上增加源点
和汇点
,将原图中每条有向边替换为容量为
的弧;增加源点
到图中每个正权顶点
的弧,容量为
;增加原图中每个负权顶点
到汇点
的弧,容量为
。于是,我们可以将图进行如下转换。
证明见论文: 胡伯涛《最小割模型在信息学竞赛中的应用》
#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;
}