HihoCoder 1398 网络流 - 最大权闭合子图
周末,小Hi和小Ho所在的班级决定举行一些班级建设活动。
根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值。
班级一共有M名学生(编号1..M),邀请编号为i的同学来参加班级建设活动需要消耗b[i]的活跃值。
每项活动都需要某些学生在场才能够进行,若其中有任意一个学生没有被邀请,这项活动就没有办法进行。
班级建设的活跃值是活动产生的总活跃值减去邀请学生所花费的活跃值。
小Hi和小Ho需要选择进行哪些活动,来保证班级建设的活跃值尽可能大。
比如有3项活动,4名学生:
第1项活动产生5的活跃值,需要编号为1、2的学生才能进行;
第2项活动产生10的活跃值,需要编号为3、4的学生才能进行;
第3项活动产生8的活跃值,需要编号为2、3、4的学生才能进行。
编号为1到4的学生需要消耗的活跃值分别为6、3、5、4。
假设举办活动集合为{1},需要邀请的学生集合为{1,2},则得到的班级活跃值为5-9 = -4。
假设举办活动集合为{2},需要邀请的学生集合为{3,4},则得到的班级活跃值为10-9 = 1。
假设举办活动集合为{2,3},需要邀请的学生集合为{2,3,4},则得到的班级活跃值为18-12 = 6。
假设举办活动集合为{1,2,3},需要邀请的学生集合为{1,2,3,4},则得到的班级活跃值为23-18 = 5。
小Hi和小Ho总是希望班级活跃值越大越好,因此在这个例子中,他们会选择举行活动2和活动3。
输入
第1行:两个正整数N,M。1≤N≤200,1≤M≤200
第2行:M个正整数,第i个数表示邀请编号为i的学生需要花费的活跃值b[i],1≤b[i]≤1,000
第3..N+2行:第i行表示编号为i的活动情况。首先是2个整数a,k,a表示该活动产生的活跃值,k表示该活动需要的学生人数。接下来k个整数列举该活动需要的学生编号。1≤a≤1,000,1≤k≤M
输出
第1行:1个整数,最大可以产生的班级活跃值
Sample Input
3 4 6 3 5 4 5 2 1 2 10 2 3 4 8 3 2 3 4
Sample Output
6
题解:最大权闭合子图裸题;
最大权闭合子图=正权点的和-最小割=正权点的和-最大流;(水题)
参考代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<queue> 6 #include<vector> 7 #include<stack> 8 #include<map> 9 #include<set> 10 #include<cmath> 11 #include<algorithm> 12 using namespace std; 13 typedef long long LL; 14 #define PI acos(-1.0) 15 #define eps 1e-8 16 #define mem(a,b) memset(a,b,sizeof a) 17 const int INF=0x3f3f3f3f; 18 const LL inf=0x3f3f3f3f3f3f3f3fLL; 19 typedef pair<int,int> P; 20 const int maxn=2010; 21 int n,m,s,t,a,k,val; 22 struct Edge{ 23 int from,to,cap,flow; 24 Edge(int _f,int _t,int _c,int _fl):from(_f),to(_t),cap(_c),flow(_fl) { } 25 }; 26 vector<Edge> edges; 27 vector<int> G[maxn]; 28 bool vis[maxn]; 29 int d[maxn],cur[maxn]; 30 31 void Init() 32 { 33 mem(d,0); 34 for(int i=0;i<=n;i++) G[i].clear(); 35 } 36 37 void Addedge(int from,int to,int cap) 38 { 39 edges.push_back(Edge(from,to,cap,0)); 40 edges.push_back(Edge(to,from,0,0)); 41 int m=edges.size(); 42 G[from].push_back(m-2); G[to].push_back(m-1); 43 } 44 45 bool bfs() 46 { 47 mem(vis,0); 48 queue<int> q; 49 q.push(s); 50 d[s]=0; vis[s]=1; 51 while(!q.empty()) 52 { 53 int x=q.front();q.pop(); 54 for(int i=0;i<G[x].size();i++) 55 { 56 Edge &e=edges[G[x][i]]; 57 if(!vis[e.to] && e.cap>e.flow) 58 { 59 vis[e.to]=1; 60 d[e.to]=d[x]+1; 61 q.push(e.to); 62 } 63 } 64 } 65 return vis[t]; 66 } 67 68 int dfs(int x,int a) 69 { 70 if(x==t || a==0) return a; 71 int flow=0,f; 72 for(int &i=cur[x];i<G[x].size();++i) 73 { 74 Edge &e=edges[G[x][i]]; 75 if(d[e.to]==d[x]+1 && (f=dfs(e.to,min(a,e.cap-e.flow)))>0) 76 { 77 e.flow+=f; 78 edges[G[x][i]^1].flow-=f; 79 flow+=f; a-=f; 80 if(a==0) break; 81 } 82 } 83 return flow; 84 } 85 86 int Maxflow(int s,int t) 87 { 88 int flow=0; 89 while(bfs()) 90 { 91 mem(cur,0); 92 flow+=dfs(s,INF); 93 } 94 return flow; 95 } 96 97 int main() 98 { 99 ios::sync_with_stdio(false); 100 cin>>n>>m; 101 int sum=0,num; 102 for(int i=1;i<=m;i++) cin>>val,Addedge(n+i,m+n+1,val); 103 for(int i=1;i<=n;i++) 104 { 105 cin>>val>>k; 106 sum+=val; 107 Addedge(0,i,val); 108 for(int j=1;j<=k;j++) 109 { 110 cin>>num; 111 Addedge(i,n+num,INF); 112 } 113 } 114 s=0,t=n+m+1; 115 int ans=sum-Maxflow(s,t); 116 cout<<ans<<endl; 117 return 0; 118 }