【CodeForces】【311E】Biologist
网络流/最大权闭合图
题目:http://codeforces.com/problemset/problem/311/E
嗯这是最大权闭合图中很棒的一道题了~
能够1A真是开心~也是我A掉的第一道E题吧……(其实是这题放在E偏水了吧……)
题目大意:有n个0/1变量,给定每个变量的初值,以及每个变量取反的费用$v_i$,有m组需求,对于第 i 组需求,如果集合$S_i$里面的每个变量的值都为给定的v(0 or 1),则获得$\omega_i$的利润,求最大总利润。(其中某些请求若是无法满足还需额外付出g的代价)
这题其实用的思路有点类似最小割……假定跟S相连的变量是选1,跟T相连的是选0,那么对于初值为1的点连i->T,容量为$v_i$,初值为0的连S->i,容量为$v_i$,表示将这些变量取反的代价。
然后考虑需求,如果是要求全为1,则对每个$S_i$中的元素$i$连边 i->n+j ,费用为INF,同时连n+j->T,容量为$\omega_i$;如果是全为0的请求则反过来。
另外这题有个特殊的要求:一些无法满足的请求需要额外付出g的代价。其实这很好解决,我们的答案是$\sum \omega_i-max_flow$,那么我们对于“朋友的请求”,就在tot+了$\omega_i$后,建边时改成容量为$\omega_i+g$即可。
# | When | Who | Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|---|---|---|
10516710 | 2015-03-29 17:21:31 | Tunix | E - Biologist | GNU C++ | Accepted | 92 ms | 28188 KB |
1 //CF 311E 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<iostream> 7 #include<algorithm> 8 #define rep(i,n) for(int i=0;i<n;++i) 9 #define F(i,j,n) for(int i=j;i<=n;++i) 10 #define D(i,j,n) for(int i=j;i>=n;--i) 11 #define pb push_back 12 using namespace std; 13 inline int getint(){ 14 int v=0,sign=1; char ch=getchar(); 15 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 16 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 17 return v*sign; 18 } 19 const int N=1e6+10,M=400020,INF=~0u>>2; 20 typedef long long LL; 21 /******************tamplate*********************/ 22 int n,m,g,tot,ans; 23 int a[N],v[N]; 24 struct edge{int to,v;}; 25 struct Net{ 26 edge E[M]; 27 int head[N],next[M],cnt; 28 void ins(int x,int y,int v){ 29 E[++cnt]=(edge){y,v}; 30 next[cnt]=head[x]; head[x]=cnt; 31 } 32 void add(int x,int y,int v){ 33 ins(x,y,v); ins(y,x,0); 34 } 35 int S,T,cur[N],d[N],Q[N]; 36 bool mklevel(){ 37 memset(d,-1,sizeof d); 38 d[S]=0; 39 int l=0,r=-1; 40 Q[++r]=S; 41 while(l<=r){ 42 int x=Q[l++]; 43 for(int i=head[x];i;i=next[i]) 44 if (d[E[i].to]==-1 && E[i].v){ 45 d[E[i].to]=d[x]+1; 46 Q[++r]=E[i].to; 47 } 48 } 49 return d[T]!=-1; 50 } 51 int dfs(int x,int a){ 52 if (x==T) return a; 53 int flow=0; 54 for(int &i=cur[x];i && flow<a;i=next[i]) 55 if (E[i].v && d[E[i].to]==d[x]+1){ 56 int f=dfs(E[i].to,min(a-flow,E[i].v)); 57 E[i].v-=f; 58 E[i^1].v+=f; 59 flow+=f; 60 } 61 if (!flow) d[x]=-1; 62 return flow; 63 } 64 void Dinic(){ 65 while(mklevel()){ 66 F(i,S,T) cur[i]=head[i]; 67 ans+=dfs(S,INF); 68 } 69 } 70 void init(){ 71 n=getint(); m=getint(); g=getint(); 72 F(i,1,n) a[i]=getint(); 73 F(i,1,n) v[i]=getint(); 74 cnt=1; S=0; T=n+m+1; ans=tot=0; 75 F(i,1,n) if(a[i]) add(S,i,v[i]);else add(i,T,v[i]); 76 F(i,1,m){ 77 int x=getint(), w=getint(), k=getint(); tot+=w; 78 F(j,1,k){ 79 int y=getint(); 80 if (!x) add(y,n+i,INF); 81 else add(n+i,y,INF); 82 } 83 int y=getint(); 84 if(y) w+=g;//if friend 85 if (!x) add(n+i,T,w); 86 else add(S,n+i,w); 87 } 88 } 89 }G1; 90 91 int main(){ 92 #ifndef ONLINE_JUDGE 93 freopen("311E.in","r",stdin); 94 freopen("311E.out","w",stdout); 95 #endif 96 G1.init(); G1.Dinic(); 97 printf("%d\n",tot-ans); 98 return 0; 99 }