BZOJ3438 小M的作物 (最小割)

BZOJ3438 小M的作物 (最小割)

模型:二者取一,体现为把点集一分为二。
源点向所有作物连边,流量为ai
所有作物向汇点连边,流量为bi
对于每组作物,新建两个点
源点向点1连一条流量为c1i的边,点2向汇点连一条流量为c2i的边
点1点2分别与组内作物连流量为inf的边
对于一个割,每个作物与源点联通代表种在A地,否则种在B地,需要割去另一部分的收益
如果组内的点不都与源点联通,则c1i必被割掉
c2i亦是如此
所以答案为总收益-最小割
卡普通Dinic,加一个弧优化既可以过了.

// luogu-judger-enable-o2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxN = 3000 + 7;
const int maxM = 5000000 + 7;
const int inf = 1e9;

int n , m, s, t;

inline int gi() {
  int x = 0,f = 1;char c = getchar();
  while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();}
  while(c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();}
  return x * f; 
} 

struct Node {
  int v,w,nex;
}Map[maxM];
int head[maxN] , dep[maxN], num = 1, cnr[maxN];

inline void add_Node(int u , int v, int w) {
    Map[++ num] = (Node) {v , w, head[u]};head[u] = num;
    Map[++ num] = (Node) {u , 0, head[v]};head[v] = num;
}

int sum;
    bool bfs() {
        memset(dep , 0, sizeof(dep));dep[s] = 1;
        memcpy(cnr,head,sizeof(head));
      queue<int>q;q.push(s);
        do {
        int u = q.front();
        q.pop();
        for(register int i = head[u];i;i = Map[i].nex) {
          int v = Map[i].v;
          if(Map[i].w && !dep[v]) {
            dep[v] = dep[u] + 1;
            q.push(v);
            if(v == t) return true;
          }
        }
      }while(!q.empty());
      return false;
    }
    
    int dfs(int now,int dist) {
      if(now == t)return dist;
      int nowflow = 0;
      for(register int i = cnr[now] ;i;i = Map[i].nex) {
        int v = Map[i].v;
        cnr[now]=i;
          if(dep[v] == dep[now] + 1 && Map[i].w) {
            int di = dfs(v,min(dist,Map[i].w));
            Map[i].w -= di;
            Map[i ^ 1].w += di;
            nowflow += di;
            dist -= di;
            if(!dist) break;
          }
      }
      return nowflow;
    }
    
    inline int Dinic() {
      int Ans = 0;
      while(bfs()) {
        while(int d = dfs(s,inf))
          Ans += d;
      }
      return Ans;
    }

int main() {
    n = gi();   s = n + 1;t = s + 1;
    for(register int i = 1;i <= n;++ i) {int w = gi();add_Node(s , i, w);sum += w;}
    for(register int i = 1;i <= n;++ i) {int w = gi();add_Node(i, t, w);sum += w;}
    m = gi();
    for(register int i = 1;i <= m;++ i) {
        int k = gi() , c1 = gi(), c2 = gi();sum = sum + c1 + c2;
        add_Node(s , n + 2 + i, c1);
        add_Node(n + m + 2 + i , t, c2);
        for(register int j = 1;j <= k;++ j) {
            int v = gi();
            add_Node(n + 2 + i, v, inf);
            add_Node(v , n + 2 + i + m, inf);
        }
    }
    printf("%d" , sum - Dinic());
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/gzygzy/p/10361046.html