• P1361 小M的作物 【网络流】【最小割】


    题目描述

    小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 = 1e6 + 7;
    const int inf = 0x3f3f3f3f;

    template<class T>inline void read(&res)
    {
        char c;T flag=1;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
        while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';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 = 1;<= n;i++) g[i].clear();
            edges.clear();
        }
        void addegde(int from,int to,int cap) {
            edges.push_back((edge){from, to, cap, 0});
            edges.push_back((edge){to, from, 0, 0});
            int m = edges.size();
            g[from].push_back(m-2);
            g[to].push_back(m-1);
        }

        int augment() {///找增广路
            int x = t,= inf;
            while(x!=s) {
                a = min(a, edges[p[x]].cap - edges[p[x]].flow);
                x = edges[p[x]].from;
            }
            x=t;
            while(!= s) {
                edges[p[x]].flow += a;
                edges[p[x]^1].flow = -a;
                x = edges[p[x]].from;
            }
            return a;
        }
        int maxflow() {///更新最大流
            int flow = 0;
            memset(num, 0, sizeof(num));
            memset(cur, 0, sizeof(cur));
            for(int i = 1; i <= n; i++) num[d[i]]++;
            int x = s;
            while(d[s] < n) {///最长的一条链上,最大的下标是nv-1,如果大于等于nv说明已断层
                if(== t) {
                    flow += augment();
                    x = s;//回退
                }
                bool ok = 0;
                for(int i = cur[x]; i < g[x].size(); i++) {
                    edge &= edges[g[x][i]];
                    if(d[x] == d[e.to] + 1 && e.cap > e.flow) {
                        p[e.to] = g[x][i];
                        cur[x] = i;= e.to;
                        ok = 1;
                        break;
                    }
                }
                if(!ok) {
                    int m = n-1;
                    for(int i = 0; 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+1;
                    num[d[x]]++;
                    cur[x] = 0;
                    if(!= s) x = edges[p[x]].from;
                }
            }
            return flow;
        }
    }ISAP;

    int n, p, q;
    int s, t;
    int tot = 0;
    int m;

    int main()
    {
        freopen("data.txt", "r", stdin);
        read(n);
        s = n + 1, t = s + 1;
        ISAP.init(* n, s, t);
        for ( int i = 1; i <= n; ++) {
            int x; read(x);
            tot += x;
            ISAP.addegde(s, i, x);
        }
        for ( int i = 1; i <= n; ++) {
            int x; read(x);
            tot += x;
            ISAP.addegde(i, t, x);
        }   
        read(m);
        for ( int i = 1; i <= m; ++) {
            int k;
            read(k);
            int suma = 0, sumb = 0;
            read(suma); read(sumb);
            tot += suma + sumb;
            ISAP.addegde(s, n + i + 2, suma);
            ISAP.addegde(+ i + m + 2, t, sumb);
            for ( int j = 1; j <= k; ++) {
                int x;
                read(x);
                ISAP.addegde(+ 2 + i, x, inf);
                ISAP.addegde(x, n + i + m + 2, inf);
            }
        }
        //cout << tot << " ! " << ISAP.maxflow() << endl;
        int mincut = ISAP.maxflow();
        printf("%d ",tot - mincut);
        return 0;
    }
  • 相关阅读:
    基于Html5的爱情主题网站–表白神器
    一个基于WebGL的仿真3D水池有逼真的水波纹效果
    一些纯css3写的公司logo
    IIS、SQL SERVER和VS的安装顺序
    SQL Server 2008 收缩日志 清空删除大日志文件
    判断SqlConnection连接是否关闭
    正则
    C# MD5加密字符串
    sqlServer MD5
    sqlserver 连接数
  • 原文地址:https://www.cnblogs.com/orangeko/p/12587338.html
Copyright © 2020-2023  润新知