问题描述
新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最优化等项目。
在前期市场调查和站址勘测之后,公司得到了一共 N 个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第 i个通讯中转站需要的成本为 \(P_i\) (1≤i≤N)。
另外公司调查得出了所有期望中的用户群,一共 M 个。关于第 i 个用户群的信息概括为 \(A_i\) , \(B_i\) 和 \(C_i\) :这些用户会使用中转站 A i 和中转站 B i 进行通讯,公司可以获益 \(C_i\) 。(1≤i≤M, 1≤\(A_i\) , \(B_i\) ≤N)
THU 集团的 CS&T 公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 – 投入成本之和)
输入格式
输入文件中第一行有两个正整数 N 和 M 。
第二行中有 N 个整数描述每一个通讯中转站的建立成本,依次为 \(P_1 , P_2 , …,P_N\) 。
以下 M 行,第(i + 2)行的三个数 \(A_i , B_i\) 和 \(C_i\) 描述第 i 个用户群的信息。
所有变量的含义可以参见题目描述。
输出格式
你的程序只要向输出文件输出一个整数,表示公司可以得到的最大净获利。
样例输入
5 5
1 2 3 4 5
1 2 3
2 3 4
1 3 3
1 4 2
4 5 3
样例输出
4
说明
样例:选择建立 1、2、3 号中转站,则需要投入成本 6,获利为 10,因此得到最大收益 4。
100%的数据中:N≤5 000,M≤50 000,0≤\(C_i\)≤100,0≤\(P_i\) ≤100。
解析
经典的二元最小割模型。
既然求最大收益,我们可以转化为理论总收益(所有可能收益的和)减去成本。考虑问题的的实际意义。从源点向每一个基站连边,容量为建造的成本,删去这条边表示放弃建立这个基站。对于每个用户群向汇点连边,容量为用户群的收益,删去这条边表示放弃这个用户群的收益。每个基站向包含自己的用户群连边,容量为inf,表示不能删。然后求最小割即可。
代码
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define N 5002 #define M 50002 using namespace std; const int inf=1<<30; int head[N+M*4],ver[M*8],nxt[M*8],cap[M*8],l; int n,m,i,s,t,dis[N+M*4],ans; int read() { char c=getchar(); int w=0; while(c<'0'||c>'9') c=getchar(); while(c<='9'&&c>='0'){ w=w*10+c-'0'; c=getchar(); } return w; } void insert(int x,int y,int z) { ver[l]=y; cap[l]=z; nxt[l]=head[x]; head[x]=l; l++; ver[l]=x; nxt[l]=head[y]; head[y]=l; l++; } bool bfs() { queue<int> q; memset(dis,-1,sizeof(dis)); q.push(s); dis[s]=0; while(!q.empty()){ int x=q.front(); q.pop(); for(int i=head[x];i!=-1;i=nxt[i]){ int y=ver[i]; if(dis[y]==-1&&cap[i]>0){ dis[y]=dis[x]+1; q.push(y); } } } return (dis[t]>0); } int dfs(int x,int flow) { if(x==t||flow==0) return flow; int ans=0; for(int i=head[x];i!=-1;i=nxt[i]){ int y=ver[i]; if(dis[y]==dis[x]+1&&cap[i]>0){ int a=dfs(y,min(flow,cap[i])); flow-=a; ans+=a; cap[i]-=a; cap[i^1]+=a; } if(flow==0) break; } if(flow) dis[x]=-1; return ans; } int main() { memset(head,-1,sizeof(head)); n=read();m=read(); t=n+m+1; for(i=1;i<=n;i++){ int w=read(); insert(s,i,w); } for(i=1;i<=m;i++){ int a=read(),b=read(),c=read(); insert(a,n+i,inf); insert(b,n+i,inf); insert(n+i,t,c); ans+=c; } while(bfs()) ans-=dfs(s,inf); printf("%d\n",ans); return 0; }
来源:https://www.cnblogs.com/LSlzf/p/12208156.html