题意
有\(n\)个\(01\)变量,你要确定它们的值,改变第\(i\)个变量的代价是\(v_i\)。
有\(m\)个限制条件,每个形如:某个变量集合内的所有元素都必须是\(0\),或者都必须是\(1\)。达成这个条件会获得\(W_i\)的收益,否则有可能会付出\(g\)的代价。
求最大收益。
sol
最大权闭合子图。转化成总收益减去最小损失来做。
最小割。假设\(S\)这边的都是\(0\),\(T\)这边的都是\(1\)。
\(n\)个变量\(n\)个点,然后每个限制条件建一个点。
对于一个原本是\(0\)的变量,连边\((S,i,v_i)\),否则连边\((i,T,v_i)\)。
对于一个限制,如果要求全都必须是\(0\),那么也就是说只要有一个\(1\)就算作不满足。集合内的所有元素连边\((i+n,x,inf)\),然后连边\((S,i+n,W_i)\)。这样子只要存在一个变量取了\(1\),这个点一定会被割在\(T\)这边,然后\(W_i\)就被算进割集里去了。
注意上述的边都是单向边。也就是说,不能存在从\(S\)跨越到\(T\)的\(inf\)边,但是从\(T\)跨越到\(S\)的\(inf\)边则是允许的。
要求全部是\(1\)同理,对每个元素连边\((x,i+n,inf)\),然后连边\((i+n,T,W_i)\)即可。
\(g\)的损失直接加到\(W_i\)里面去就好了。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 15000;
const int inf = 1e9;
struct edge{int to,nxt,w;}a[N*10];
int n,m,g,sex[N],S,T,head[N],cnt=1,dep[N],cur[N],ans;
queue<int>Q;
void link(int u,int v,int w)
{
a[++cnt]=(edge){v,head[u],w};
head[u]=cnt;
a[++cnt]=(edge){u,head[v],0};
head[v]=cnt;
}
bool bfs()
{
memset(dep,0,sizeof(dep));
dep[S]=1;Q.push(S);
while (!Q.empty())
{
int u=Q.front();Q.pop();
for (int e=head[u];e;e=a[e].nxt)
if (a[e].w&&!dep[a[e].to])
dep[a[e].to]=dep[u]+1,Q.push(a[e].to);
}
return dep[T];
}
int dfs(int u,int f)
{
if (u==T) return f;
for (int &e=cur[u];e;e=a[e].nxt)
if (a[e].w&&dep[a[e].to]==dep[u]+1)
{
int tmp=dfs(a[e].to,min(a[e].w,f));
if (tmp) {a[e].w-=tmp;a[e^1].w+=tmp;return tmp;}
}
return 0;
}
int Dinic()
{
int res=0;
while (bfs())
{
for (int i=1;i<=T;++i) cur[i]=head[i];
while (int tmp=dfs(S,inf)) res+=tmp;
}
return res;
}
int main()
{
n=gi();m=gi();g=gi();S=n+m+1;T=S+1;
for (int i=1;i<=n;++i) sex[i]=gi();
for (int i=1;i<=n;++i)
{
int x=gi();
sex[i]?link(i,T,x):link(S,i,x);
}
for (int i=1;i<=m;++i)
{
int v=gi(),w=gi(),k=gi();ans+=w;
while (k--)
{
int x=gi();
v?link(x,i+n,inf):link(i+n,x,inf);
}
int gg=gi();w+=g*gg;
v?link(i+n,T,w):link(S,i+n,w);
}
printf("%d\n",ans-Dinic());
return 0;
}