题目描述

小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号)。

现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益,小M找到了规则中共有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以获得c2i的额外收益。

小M很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?

输入格式

第一行包括一个整数n

第二行包括n个整数,表示ai第三行包括n个整数,表示bi第四行包括一个整数m接下来m行,

对于接下来的第i行:第一个整数ki,表示第i个作物组合中共有ki种作物,

接下来两个整数c1i,c2i,接下来ki个整数,表示该组合中的作物编号。

输出格式

只有一行,包括一个整数,表示最大收益

输入输出样例

输入 #1复制

3
4 2 1
2 3 2
1
2 3 2 1 2
输出 #1复制

11

说明/提示

样例解释

A耕地种1,2,B耕地种3,收益4+2+3+2=11。

数据范围与约定

1<=k< n<= 1000,0 < m < = 1000 保证所有数据及结果不超过2*10^9。

思路

  如果把农作物作为中间点,农场 A 设为源, B 设为汇。

  因为对于每个农作物只能种在一个农场中,所以该题可以等效为一个最小割模型。

  所以如何对 bonus 的组合建边是关键。

  把整个组合点集看作是一个点并拆成出入两点,由A有一条到入点的路,且从出点有一条到B的路,再逐次将待加入的点添加进点集就可以了。

  这样能获得的最大值就是总价值 - 最小割

CODE

  

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = e + ;
const int inf = 0x3f3f3f3f;
template<class T>inline void read(T &res)
{
    char c;T flag=;
    while((c=getchar())<''||c>'')if(c=='-')flag=-;res=c-'';
    while((c=getchar())>=''&&c<='')res=res*+c-'';res*=flag;
}
struct edge{int from,to,cap,flow;};
struct isap
{
    int n,s,t,p[maxn],d[maxn],cur[maxn],num[maxn];
    bool vis[maxn];
    vector<int>g[maxn];
    vector<edge>edges;
    void init(int n,int s,int t) {
        this->n = n;
        this->s = s;
        this->t = t;
        for(int i = ;i <= n;i++) g[i].clear();
        edges.clear();
    }
    void addegde(int from,int to,int cap) {
        edges.push_back((edge){from, to, cap, });
        edges.push_back((edge){to, from, , });
        int m = edges.size();
        g[from].push_back(m-);
        g[to].push_back(m-);
    }
    int augment() {///找增广路
        int x = t,a = inf;
        while(x!=s) {
            a = min(a, edges[p[x]].cap - edges[p[x]].flow);
            x = edges[p[x]].from;
        }
        x=t;
        while(x != s) {
            edges[p[x]].flow += a;
            edges[p[x]^].flow = -a;
            x = edges[p[x]].from;
        }
        return a;
    }
    int maxflow() {///更新最大流
        int flow = ;
        memset(num, , sizeof(num));
        memset(cur, , sizeof(cur));
        for(int i = ; i <= n; i++) num[d[i]]++;
        int x = s;
        while(d[s] < n) {///最长的一条链上,最大的下标是nv-1,如果大于等于nv说明已断层
            if(x == t) {
                flow += augment();
                x = s;//回退
            }
            bool ok = ;
            for(int i = cur[x]; i < g[x].size(); i++) {
                edge &e = edges[g[x][i]];
                if(d[x] == d[e.to] +  && e.cap > e.flow) {
                    p[e.to] = g[x][i];
                    cur[x] = i;x = e.to;
                    ok = ;
                    break;
                }
            }
            if(!ok) {
                int m = n-;
                for(int i = ; i < g[x].size();i++) {
                    edge &e=edges[g[x][i]];
                    if(e.cap>e.flow) m=min(m,d[e.to]);
                }
                num[d[x]]--;
                if(!num[d[x]]) break;
                d[x] = m+;
                num[d[x]]++;
                cur[x] = ;
                if(x != s) x = edges[p[x]].from;
            }
        }
        return flow;
    }
}ISAP;
int n, p, q;
int s, t;
int tot = ;
int m;
int main()
{
    freopen("data.txt", "r", stdin);
    read(n);
    s = n + , t = s + ;
    ISAP.init(n * n, s, t);
    for ( int i = ; i <= n; ++i ) {
        int x; read(x);
        tot += x;
        ISAP.addegde(s, i, x);
    }
    for ( int i = ; i <= n; ++i ) {
        int x; read(x);
        tot += x;
        ISAP.addegde(i, t, x);
    }   
    read(m);
    for ( int i = ; i <= m; ++i ) {
        int k;
        read(k);
        int suma = , sumb = ;
        read(suma); read(sumb);
        tot += suma + sumb;
        ISAP.addegde(s, n + i + , suma);
        ISAP.addegde(n + i + m + , t, sumb);
        for ( int j = ; j <= k; ++j ) {
            int x;
            read(x);
            ISAP.addegde(n +  + i, x, inf);
            ISAP.addegde(x, n + i + m + , inf);
        }
    }
    //cout << tot << " ! " << ISAP.maxflow() << endl;
    int mincut = ISAP.maxflow();
    printf("%d\n",tot - mincut);
    return ;
}

P1361 小M的作物 【网络流】【最小割】的更多相关文章

  1. 【bzoj3438】小M的作物 网络流最小割

    原文地址:http://www.cnblogs.com/GXZlegend/p/6801522.html 题目描述 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物 ...

  2. BZOJ_3438_小M的作物_最小割

    BZOJ_3438_小M的作物_最小割 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子 有1个(就是可以种一棵作物) ...

  3. BZOJ3438 小M的作物(最小割)

    题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=3438 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为 ...

  4. 「BZOJ3438」小M的作物(最小割

    3438: 小M的作物 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1891  Solved: 801[Submit][Status][Discus ...

  5. 【洛谷1361】 小M的作物(最小割)

    传送门 洛谷 Solution 这是一个比较实用的套路,很多题目都有用,而且这个套路难以口胡出来. 考虑把每一个附加贡献重新建一个点,然后向必需的点连边,流量为val. 然后直接种植的从源点向这个点连 ...

  6. P1361 小M的作物

    P1361 小M的作物 题目描述 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号). 现在,第 ...

  7. 洛谷 P1361 小M的作物 解题报告

    P1361 小M的作物 题目描述 小M在MC里开辟了两块巨大的耕地\(A\)和\(B\)(你可以认为容量是无穷),现在,小\(P\)有\(n\)中作物的种子,每种作物的种子有1个(就是可以种一棵作物) ...

  8. luogu P1361 小M的作物

    题目链接 luogu P1361 小M的作物 题解 源汇点为A,B 向种子连边,容量为价值,每个种子能与A或B联通,考虑最小割 用建边的总流量减去最小割就是答案 相同利益的时候新建节点,由额外利益构成 ...

  9. P1361 小M的作物 (最大流)

    题目 P1361 小M的作物 解析 把\(A\)看做源点,把\(B\)看做汇点,先不考虑额外情况 显然,这是一种两者选其一的问题,我们选择一部分边割去,使这部分边的贡献最小,就是求最小割,我们求出了收 ...

  10. 【bzoj3774】最优选择 网络流最小割

    题目描述 小N手上有一个N*M的方格图,控制某一个点要付出Aij的代价,然后某个点如果被控制了,或者他周围的所有点(上下左右)都被控制了,那么他就算是被选择了的.一个点如果被选择了,那么可以得到Bij ...

随机推荐

  1. Java遍历文件夹的两种方法(非递归和递归)

    import java.io.File; import java.util.LinkedList; public class FileSystem {    public static int num ...

  2. Django 学习笔记1-- URLconf

    今天好像巴黎有点乱,希望明天太阳还会照常升起. 简介 Django 是一个由 Python 编写.开源并采用经典的 MVC 设计模式的 Web Full Stack 应用框架. 在 Django 中, ...

  3. Lambda表达式和函数试接口的最佳实践 · LiangYongrui's Studio

    1.概述 本文主要深入研究java 8中的函数式接口和Lambda表达式,并介绍最佳实践. 2.使用标准的函数式接口 包java.util.function中的函数是接口已经可以满足大部分的java开 ...

  4. 学习日记:Python爬虫-1

    这几天在b站看小甲鱼的python3教程,照着写了个有道翻译的程序 代码中字典data中的内容,用浏览器审查元素,先随便输一个要翻译的,找到跳出来的post的那个网址,看formdata就行了 返回的 ...

  5. vector 循环里删除多个元素

    ; i < (int)vecLines.size(); i++) { AcDbLine * l1 = vecLines[i]; if (l1 == NULL) { continue; } //记 ...

  6. 关于响应式web设计

    手机网站+电脑网站+平版网站 = 响应式网站 在没有足够经费跟精力的做一个手机网站的情况下,响应式网站是个不错的选择.它有以下的优点: 减少工作量(网站代码只要一份,只需要做js方面的改动及可以了) ...

  7. 微信小程序学习简介

    如何向微信小程序导入DEMO源码: 参考方法 参考学习小程序官方文档 小程序官方文档 小程序目录简介 app.json :设置一些工程全局的量.js : 写一些函数逻辑.wxml: 调用.js中写的函 ...

  8. #AcWing系列课程Level-2笔记——5.高精度“+”算法

    高精度"+"算法 编写高精度"+",记住下面的过程,代码也就游刃有余了! 1.首先我们要明白大整数是如何存储的? 2.其次存储完,如何运算? 高精度" ...

  9. java算法--普通队列

    数据结构队列 首先明确一下队列的概念. 队列是一种有序列表,使用数组的结构来存储队列的数据. 队列是一种先进先出的算法.由前端加入,由后端输出. 如下图: ​ 第一个图 第二个图 第三个图 这就是队列 ...

  10. Markdown使用说明

    # Markdown 使用说明 Markdown 是一种**轻量级标记语言** 使用规则: 1. 标题   2. 列表 3. 引用 4. 图片与链接 5. 粗体与斜体 6.表格 7. 代码框 8. 分 ...