题目大意
有一个长度为 \(n\) 的 01 串,将第 \(i\) 个位置变为另外一个数字的代价是\(v_i\) 。 有 \(m\) 个要求 每个要求的形式是 首先确定若干位置都要是 \(0\) 或者 \(1\)
然后给定这 \(k\) 个位置,如果些位置上都满足要求 那么就可以得到 \(W_k\) 元 某些要求如果失败了还要倒着给\(g\) 元。问最终能够得到的最大利润
输入格式: 第一行是 \(n,m,g\)
第二行是初始的 01 串 第三行是 \(V_i\)
接下来 \(m\) 行 第一个数字表示这个集合都要是 0 还是 1
第二个数字 \(W_i\) 表示利润,接下来 \(k_i\) 表示这个集合中有 \(k\) 个位置 接下来是这 \(k\) 个位置, 最后还有一个 0/1 ,如果是 1 ,表示如果失败了还要倒着给 \(g\) 元。
解析
一道非常满足最小割模型的题目。对于每个点,如果最开始是0,我们从原点向它连边,边权为\(v_i\),表示这个点不为0的代价。同理,对于一个为1的点,将它向汇点连边,边权为\(v_i\),表示该点不为1的代价。
对于每一组要求,如果是要全为0,就从原点向这个要求对应的点连边,边权为这个要求不满足的代价(包括\(w_i\)以及是否有额外代价)。然后从要求对应的边向要求中的点连边,边权为无穷大。如果要求全为1,就从这个要求对应的点向汇点连边,边权为这个要求不满足的代价。然后从要求中的点向这个点连边,边权无穷大。用总代价减去最小割即为答案。
代码
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define N 20002 #define M 2000002 using namespace std; const int inf=1<<30; int head[N],ver[M],nxt[M],cap[M],l; int n,m,g,s,t,i,j,a[N],v[N],dis[N],ans; int read() { char c=getchar(); int w=0; while(c<'0'||c>'9') c=getchar(); while(c<='9'&&c>='0'){ w=w*10+c-'0'; c=getchar(); } return w; } void insert(int x,int y,int z) { ver[l]=y; cap[l]=z; nxt[l]=head[x]; head[x]=l; l++; ver[l]=x; nxt[l]=head[y]; head[y]=l; l++; } bool bfs() { queue<int> q; memset(dis,-1,sizeof(dis)); q.push(s); dis[s]=0; while(!q.empty()){ int x=q.front(); q.pop(); for(int i=head[x];i!=-1;i=nxt[i]){ int y=ver[i]; if(dis[y]==-1&&cap[i]>0){ dis[y]=dis[x]+1; q.push(y); } } } return (dis[t]>0); } int dfs(int x,int flow) { if(x==t||flow==0) return flow; int ans=0; for(int i=head[x];i!=-1;i=nxt[i]){ int y=ver[i]; if(dis[y]==dis[x]+1&&cap[i]>0){ int a=dfs(y,min(flow,cap[i])); ans+=a; flow-=a; cap[i]-=a; cap[i^1]+=a; } if(flow==0) break; } if(flow) dis[x]=-1; return ans; } int Dinic() { int ans=0; while(bfs()) ans+=dfs(s,inf); return ans; } int main() { memset(head,-1,sizeof(head)); n=read();m=read();g=read(); t=n+m+1; for(i=1;i<=n;i++) a[i]=read(); for(i=1;i<=n;i++) v[i]=read(); for(i=1;i<=n;i++){ if(a[i]==0) insert(s,i,v[i]); else insert(i,t,v[i]); } for(i=1;i<=m;i++){ int op=read(),w=read(),k=read(); if(op==0){ for(j=1;j<=k;j++){ int x=read(); insert(n+i,x,inf); } int flag=read(); if(flag) insert(s,n+i,w+g); else insert(s,n+i,w); ans+=w; } else{ for(j=1;j<=k;j++){ int x=read(); insert(x,n+i,inf); } int flag=read(); if(flag) insert(n+i,t,w+g); else insert(n+i,t,w); ans+=w; } } printf("%d\n",ans-Dinic()); return 0; }
来源:https://www.cnblogs.com/LSlzf/p/12234812.html