题面
https://www.luogu.org/problem/CF311E
题解
最小割,加点表示限制,三叉戟模型。
不让割$->$割了没用。
一定割$->$不割就联通。
#include<map> #include<stack> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define N 20050 #define S 0 #define T (n+1) #define LL long long #define ri register int #define INF 1000000007 using namespace std; int n,m,g; int s[N],v[N]; struct graph { vector<int> ed[N]; vector<int> w,to; int d[N],cur[N]; void add_edge(int u,int v,int tw) { to.push_back(v); w.push_back(tw); ed[u].push_back(to.size()-1); to.push_back(u); w.push_back(0); ed[v].push_back(to.size()-1); } bool bfs() { queue<int> q; memset(d,0x3f,sizeof(d)); d[S]=0; q.push(S); while (!q.empty()) { int x=q.front(); q.pop(); for (ri i=0;i<ed[x].size();i++) { int e=ed[x][i]; if (d[x]+1<d[to[e]] && w[e]) { d[to[e]]=d[x]+1; q.push(to[e]); } } } return d[T]<INF; } int dfs(int x,int limit) { if (x==T || limit==0) return limit; int sum=0; for (ri &i=cur[x];i<ed[x].size();i++) { int e=ed[x][i]; if (w[e] && d[x]+1==d[to[e]]) { int f=dfs(to[e],min(limit,w[e])); if (!f) continue; sum+=f; limit-=f; w[e]-=f; w[1^e]+=f; if (!limit) return sum; } } return sum; } int dinic() { int ret=0; while (bfs()) { memset(cur,0,sizeof(cur)); ret+=dfs(S,INF); } return ret; } } G; int main() { int ss,w,x,k,s2; scanf("%d %d %d",&n,&m,&g); for (ri i=1;i<=n;i++) scanf("%d",&s[i]); for (ri i=1;i<=n;i++) { scanf("%d",&v[i]); if (s[i]) G.add_edge(i,T,v[i]); else G.add_edge(S,i,v[i]); } int sum=0; int cc=n+1; for (ri i=1;i<=m;i++) { scanf("%d",&ss); scanf("%d",&w); sum+=w; scanf("%d",&k); ++cc; if (!ss) G.add_edge(S,cc,w); else G.add_edge(cc,T,w); for (ri j=1;j<=k;j++) { scanf("%d",&x); if (!ss) G.add_edge(cc,x,INF); else G.add_edge(x,cc,INF); } scanf("%d",&s2); if (s2) { if (!ss) G.add_edge(S,cc,g); else G.add_edge(cc,T,g); } } printf("%d\n",sum-G.dinic()); return 0; }