zoukankan      html  css  js  c++  java
  • 4682. 【GDOI2017模拟8.11】生物学家

    Description

    经过多年的努力, Philipsweng 在生物和计算机领域取得卓越成就。并研究出可以使牛变性的基因重组技术,获得 20XX 年诺贝尔医学或生理学奖。
    现在,Philipsweng 有 \(n\) 头牛,牛从 1 到 \(n\) 编号。最开始时,每头牛都有一个性别 \(s_i\) ( 0 表示雌,1 表示雄),由于牛与牛之间的基因是不同的,所以使第 \(i\) 头牛变性需要 \(v_i\) 元的花费。
    即使 Philipsweng 家很有钱,但是,也承担不起多年的研究费用。这时他就需要一些富豪朋友去资助,例如 dengwxn 等等。

    Philipsweng 一共有 \(m\) 位朋友,每位朋友可以资助 \(w_i\) 元,当然, 世上没有免费的午餐。他们会提出一些苛刻的条件。他会选定 \(k_i\) 头牛,以及一个性别,如果最终这 \(k_i\) 头牛都为选定的性别,则满足,否则不满足。Philipsweng 还有一些好朋友,例如 Jason 等等,如果 Philipsweng 不能满足好朋友的条件,不仅不能获得 \(w_i\) 的收益,而且要花 \(g\) 元请好朋友喝茶。

    Solution

    答案=所有赞助费-变性费用-没拿到的赞助费-请喝茶的费用。

    所有的赞助费是已知的,要最大化答案,就是要最小化后面那部分。

    因此可以想到最小割,建源点 \(S\) 表示雄性,\(T\) 表示雌性。

    然后 \(S\) 向所有雄性牛连边,流量是 \(v_i\)。雌性牛向 \(T\) 连边,代价同理。

    然后考虑将朋友也放到图中。

    如果朋友要求雄性,就 $S\to n+i\to $ 牛。代价分别是 \(w_i(+g)\)\(inf\)(因为要保证这条边绝对不被割掉)。反之亦然。

    那么此时割牛边相当于变性,给人边相当于不要某人的赞助费。

    然后就可以愉快的跑最大流了。

    Code

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 10005
    #define inf 107374180
    using namespace std;
    struct node
    {
        int to,next,head,flow;
    }a[200005];
    queue<int> q;
    int n,m,g,S,T,tot=1,xxb,gg,k,x,isf,ans,xb[N],v[N],cur[N<<1],dep[N<<1];
    int read()
    {
        int res=0;char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch-'0'),ch=getchar();
        return res;
    }
    void add(int x,int y,int z)
    {
        a[++tot].to=y;
        a[tot].flow=z;
        a[tot].next=a[x].head;
        a[x].head=tot;
    }
    bool bfs()
    {
        for (int i=1;i<=n+m+2;++i)
            dep[i]=0;
        while (!q.empty()) q.pop();
        dep[S]=1;q.push(S);
        while (!q.empty())
        {
            int x=q.front();q.pop();
            for (int i=a[x].head;i;i=a[i].next)
            {
                if (a[i].flow>0&&dep[a[i].to]==0)
                {
                    dep[a[i].to]=dep[x]+1;
                    q.push(a[i].to);
                    if (a[i].to==T) return true;
                }
            }
        }
        return false;
    }
    int dfs(int x,int ff)
    {
        if (x==T) return ff;
        int fw=0;
        for (int &i=cur[x];i;i=a[i].next)
        {
            if (a[i].flow>0&&dep[a[i].to]==dep[x]+1)
            {
                int f=dfs(a[i].to,min(a[i].flow,ff));
                a[i].flow-=f;
                a[i^1].flow+=f;
                fw+=f;
                ff-=f;
                if (ff<=0) break;
            }
        }
        return fw;
    }
    int dinic()
    {
        int res=0;
        while (bfs())
        {
            for (int i=1;i<=n+m+2;++i)
                cur[i]=a[i].head;
            res+=dfs(S,inf);
        }
        return res;
    }
    int main()
    {
        n=read();m=read();g=read();
        S=n+m+1;T=n+m+2;
        for (int i=1;i<=n;++i)
            xb[i]=read();
        for (int i=1;i<=n;++i)
            v[i]=read();
        for (int i=1;i<=n;++i)
        {
            if (xb[i]==1) add(S,i,v[i]),add(i,S,0);
            else add(i,T,v[i]),add(T,i,0);
        }
        for (int i=1;i<=m;++i)
        {
            xxb=read();gg=read();
            ans+=gg;
            k=read();
            for (int j=1;j<=k;++j)
            {
                x=read();
                if (xxb==1) add(n+i,x,inf),add(x,n+i,0);
                else add(x,n+i,inf),add(n+i,x,0);
            }
            isf=read();
            if (isf==1) gg+=g;
            if (xxb==1) add(S,n+i,gg),add(n+i,S,0);
            else add(n+i,T,gg),add(T,n+i,0);
        }
        printf("%d\n",ans-dinic());
        return 0;
    }
    
  • 相关阅读:
    win10上使用linux命令
    leetcode--js--Median of Two Sorted Arrays
    leetcode--js--Longest Substring Without Repeating Characters
    Linux常用的命令
    微信小程序
    leetcode—js—Add Two Numbers
    PHPExcel使用
    console控制台的用法
    git中常混淆的操作
    mysql解析json下的某个字段
  • 原文地址:https://www.cnblogs.com/Livingston/p/15730820.html
Copyright © 2011-2022 走看看