说明:S,表示超级原点,T表示超级汇点,<i,j,k(,l)>表示i到j建边,流量为k(,费用为l),某些题由于没有及时纠正码风,板子的常数较大。。。。。
bzoj4177 Mike的农场
题解:考虑割,养牛的收益为a[i],养羊b[i],对于每个位置<S,i,ai> <i,T,bi>分别表示养牛和养羊,对于两个互相影响的位置<i,j,ci>;做最小割可以满足前两个限制 ;第三个限制,如果全养牛可以获得d,新建一个点x,考虑要求全养牛的位置为集合为s,<S,x,d> , <x,si,inf> , 当si中有一个没有被割,那么<S,x,d>一定被割,养羊同理对T建,设最小割为C,ans = $( \sum (a[i]+b[i]) + \sum c[i] ) – C $
1 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 const int N=10010,M=80010; 5 int S,T,n,m,k,o,hd[N],cur[N],vis[N],d[N]; 6 struct Edge{int v,nt,c,f;}E[M<<1]; 7 char gc(){ 8 static char*p1,*p2,s[1000000]; 9 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 10 return(p1==p2)?EOF:*p1++; 11 } 12 int rd(){ 13 int x=0; char c=gc(); 14 while(c<'0'||c>'9')c=gc(); 15 while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc(); 16 return x; 17 } 18 void adde(int u,int v,int c){ 19 E[o]=(Edge){v,hd[u],c,0};hd[u]=o++; 20 E[o]=(Edge){u,hd[v],0,0};hd[v]=o++; 21 } 22 queue<int>q; 23 bool bfs(){ 24 for(int i=S;i<=T;i++)vis[i]=d[i]=0; 25 vis[S]=d[S]=1;q.push(S); 26 while(!q.empty()){ 27 int u=q.front();q.pop(); 28 for(int i=hd[u],v;~i;i=E[i].nt)if(E[i].c>E[i].f){ 29 if(!vis[v=E[i].v])vis[v]=1,d[v]=d[u]+1,q.push(v); 30 } 31 } 32 return vis[T]; 33 } 34 int dfs(int u,int F){ 35 if(u==T||!F)return F; 36 int flow=0,f; 37 for(int i=cur[u];~i;i=E[i].nt){ 38 int v=E[cur[u]=i].v; 39 if(d[v]==d[u]+1&&(f=dfs(v,min(E[i].c-E[i].f,F)))){ 40 flow+=f,F-=f; 41 E[i].f+=f,E[i^1].f-=f; 42 if(!F)break; 43 } 44 } 45 return flow; 46 } 47 int dinic(){ 48 int flow=0; 49 while(bfs()){for(int i=S;i<=T;i++)cur[i]=hd[i];flow+=dfs(S,inf);} 50 return flow; 51 } 52 int main(){ 53 freopen("bzoj4177.in","r",stdin); 54 freopen("bzoj4177.out","w",stdout); 55 n=rd();m=rd();k=rd(); 56 S=0,T=n+k+1; 57 for(int i=S;i<=T;i++)hd[i]=-1; 58 int ans=0; 59 for(int i=1,x;i<=n;i++){adde(S,i,x=rd());ans+=x;} 60 for(int i=1,x;i<=n;i++){adde(i,T,x=rd());ans+=x;} 61 for(int i=1,x,y,z;i<=m;i++){ 62 x=rd();y=rd();z=rd(); 63 adde(x,y,z); 64 adde(y,x,z); 65 } 66 for(int i=1,t,a,b;i<=k;i++){ 67 t=rd();a=rd();b=rd(); 68 ans+=b; 69 if(!a){ 70 adde(S,i+n,b); 71 for(int j=1;j<=t;j++)adde(i+n,rd(),inf); 72 }else{ 73 adde(i+n,T,b); 74 for(int j=1;j<=t;j++)adde(rd(),i+n,inf); 75 } 76 } 77 ans -= dinic(); 78 printf("%d\n",ans); 79 return 0; 80 } 81 82 83 84 85 86 87 88 89 90 //一个很好的割; 91 //每个点(S,i,a[i]) (i,T,b[i]); 92 //相同时代价 (x,y,b) 93 //集合的贡献:新建n+i号节点表示:a==0 , (S,n+i,b) (n+i,si,inf) ; a==1 (si,n+i,inf) (n+i,T,b); 94 //用总的正值减去最小割即可; 95 //注意第三步; 96 //20181210 97