NOI2006 最大获利(最大权闭合子图)
codevs 1789 最大获利
2006年NOI全国竞赛
新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是 挑战。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 和 M 。 第二行中有 N 个整数描述每一个通讯中转站的建立成本,依次为 P1, P2, …, PN 。 以下 M 行,第(i + 2)行的三个数 Ai, Bi和 Ci描述第 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。
80%的数据中:N≤200,M≤1 000。
100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。
最大权闭合子图
源点向所有用户连流量为收益的边
所有中转站向汇点连流量为成本的边
用户所需要的中转站,由用户向需要的中转站连inf边
然后用所有用户收益和-最小割
#include<cstdio> #include<queue> #include<algorithm> #define N 55010 #define M 50001 #define inf 2e9 using namespace std; int n,m,tot=1; int src,dec,sum; int lev[N],cur[N],front[N],cap[M*10],to[M*10],next[M*10]; queue<int>q; void add(int u,int v,int w) { to[++tot]=v;next[tot]=front[u];front[u]=tot;cap[tot]=w; to[++tot]=u;next[tot]=front[v];front[v]=tot;cap[tot]=0; } bool bfs() { for(int i=0;i<=dec;i++) {lev[i]=-1;cur[i]=front[i];} while(!q.empty()) q.pop(); q.push(src);lev[src]=0; while(!q.empty()) { int now=q.front();q.pop(); for(int i=front[now];i;i=next[i]) { int t=to[i]; if(cap[i]>0&&lev[t]==-1) { lev[t]=lev[now]+1; if(t==dec) return true; q.push(t); } } } return false; } int dinic(int now,int flow) { if(now==dec) return flow; int rest=0,delta; for(int & i=cur[now];i;i=next[i]) { int t=to[i]; if(cap[i]>0&&lev[t]>lev[now]) { delta=dinic(t,min(cap[i],flow-rest)); if(delta) { cap[i]-=delta;cap[i^1]+=delta; rest+=delta;if(rest==flow) break; } } } if(rest!=flow) lev[now]=-1; return rest; } int main() { scanf("%d%d",&n,&m); dec=n+m+1; int x,y,z; for(int i=1;i<=n;i++) { scanf("%d",&x); add(i,dec,x); } for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); add(src,n+i,z); add(n+i,x,inf); add(n+i,y,inf); sum+=z; } while(bfs()) sum-=dinic(src,inf); printf("%d",sum); }
空间问题,今天下午第n次开小空间