最大权闭合子图BZOJ1497[NOI2006]-最大获利
Posted Yiyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最大权闭合子图BZOJ1497[NOI2006]-最大获利相关的知识,希望对你有一定的参考价值。
【题目大意】
建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)
【思路】
根据最大权闭合子图的结论进行建图,超级源点和中转站相连,容量为成本;A与B中转站分别连向某个用户,容量为INF;再由某个用户连向超级汇点,容量为收益值。
最终答案=∑(所有用户群的总收益)-最大流。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cstdlib> 7 #include<vector> 8 #include<cmath> 9 #include<queue> 10 #define target m+n+1 11 using namespace std; 12 const int MAXN=600000; 13 const int INF=0x7fffffff; 14 struct node 15 { 16 int to,pos,cap; 17 }; 18 vector<node> E[MAXN]; 19 int n,m; 20 int sum=0; 21 int vis[MAXN]; 22 int dist[MAXN]; 23 24 void addedge(int u,int v,int w) 25 { 26 E[u].push_back((node){v,E[v].size(),w}); 27 E[v].push_back((node){u,E[u].size()-1,0}); 28 } 29 30 void init() 31 { 32 scanf("%d%d",&n,&m); 33 for (int i=1;i<=n;i++) 34 { 35 int p; 36 scanf("%d",&p); 37 addedge(0,i,p); 38 } 39 for (int i=1;i<=m;i++) 40 { 41 int a,b,c; 42 scanf("%d%d%d",&a,&b,&c); 43 addedge(a,i+n,INF); 44 addedge(b,i+n,INF); 45 addedge(i+n,target,c); 46 sum+=c; 47 } 48 } 49 50 int bfs() 51 { 52 memset(dist,-1,sizeof(dist)); 53 queue<int> que; 54 while (!que.empty()) que.pop(); 55 que.push(0); 56 dist[0]=0; 57 58 while (!que.empty()) 59 { 60 int head=que.front(); 61 que.pop(); 62 for (int i=0; i<E[head].size(); i++) 63 { 64 node &tmp=E[head][i]; 65 if (dist[tmp.to]==-1 && tmp.cap>0) 66 { 67 dist[tmp.to]=dist[head]+1; 68 que.push(tmp.to); 69 if (tmp.to==target) return 1; 70 } 71 } 72 } 73 return 0; 74 } 75 76 77 int dfs(int s,int e,int f) 78 { 79 int ret=0; 80 if (s==e || f==0) return(f); 81 for (int i=0; i<E[s].size(); i++)//此处可添加当前弧优化,但是效率反而会低orz 82 { 83 node &tmp=E[s][i]; 84 if (dist[tmp.to]==dist[s]+1 && tmp.cap>0) 85 { 86 int delta=dfs(tmp.to,e,min(tmp.cap,f)); 87 if (delta>0) 88 { 89 ret+=delta; 90 tmp.cap-=delta; 91 E[tmp.to][tmp.pos].cap+=delta; 92 f-=delta;//不要忘记f要减去delta! 没有加的时候是60s,加了ret累加后瞬间快了 93 } 94 } 95 } 96 return ret; 97 } 98 99 void dinic() 100 { 101 int flow=0; 102 while (bfs()) 103 { 104 for (;;) 105 { 106 memset(vis,0,sizeof(vis)); 107 int f=dfs(0,target,INF); 108 if (f==0) break; 109 else flow+=f; 110 } 111 } 112 int ans=sum-flow; 113 cout<<ans<<endl; 114 } 115 116 int main() 117 { 118 init(); 119 dinic(); 120 return 0; 121 }
以上是关于最大权闭合子图BZOJ1497[NOI2006]-最大获利的主要内容,如果未能解决你的问题,请参考以下文章