【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$即可。

#WhenWhoProblemLangVerdictTimeMemory
105167102015-03-29 17:21:31Tunix E - Biologist GNU C++Accepted92 ms28188 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 }
View Code

 

  

转载于:https://www.cnblogs.com/Tunix/p/4376622.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值