【CF311EB】Biologist

题面

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;
}

 

上一篇:#0/1分数规划,二分,树上背包,DFS序#洛谷 4322 JZOJ 4512 BZOJ 4753 最佳团体


下一篇:【BZOJ3232】圈地游戏