bzoj 4177 Mike的农场

bzoj 4177 Mike的农场

  • 思维有些江化了,一上来就想费用流做法,但其实就是个最小割啊.
  • 考虑先将所有的收益拿到,再减去不能拿的以及三元组 \((i,j,k)\) 产生的代价.即,先让 \(ans=\sum a_i+b_i+\sum_{(S,a,b)} b\).
  • 然后要让减去的最小,尝试构造一个最小割模型.建一个源点 \(S\) ,一个汇点 \(T\) .
  • 为了满足每个点只能选一种动物,从 \(S\) 向每个点 \(i\) 连权值为 \(a_i\) 的边,从每个点 \(i\) 向 \(T\) 连权值为 \(b_i\) 的边.
  • 为了处理三元组 \((i,j,k)\) ,对每个这样的三元组,在 \(i \to j,j\to i\) 都连一条权值为 \(k\) 的边.这样只要两者割的不一样,就还需要割掉中间的这条边.
  • 为了处理三元组 \((S,a,b)\) ,新建一个点 \(np\) ,若 \(a=0\) , 就从 \(S\) 向 \(np\) 连一条权值为 \(b\) 的边,从 \(np\) 向 \(\forall i\in S\) 连一条权值为 \(inf\) 的边.这样要么割掉这个收益 \(b\) ,要么就全部割羊的边,即全选牛.
  • \(a=1\) 同理,从 \(np\) 向 \(T\) 连一条权值为 \(b\) 的边,从 \(\forall i\in S\) 向 \(np\) 连一条权值为 \(inf\) 的边.
  • 建出图后跑一跑最小割,用 \(ans\) 减去它即得答案.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 1e18
inline ll read()
{
    ll out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int MAXN=1e6+10;
int cnt=-1,head[MAXN],nx[MAXN],to[MAXN];
ll flow[MAXN];
void addedge(int u,int v,ll Flow)
{
    ++cnt;
    to[cnt]=v;
    nx[cnt]=head[u];
    flow[cnt]=Flow;
    head[u]=cnt;
}
void ins(int u,int v,ll Flow)
{
    addedge(u,v,Flow);
    addedge(v,u,0);
}
int tot=0;
int cur[MAXN],dep[MAXN];
ll maxflow=0;
bool bfs(int S,int T)
{
    for(int i=1;i<=tot;++i)
        dep[i]=-1;
    for(int i=1;i<=tot;++i)
        cur[i]=head[i];
    dep[S]=0;
    queue<int> q;
    q.push(S);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=nx[i])
        {
            int v=to[i];
            if(flow[i] && dep[v]==-1)
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    if(dep[T]==-1)
        return false;
    return true;
}
ll dfs(int u,int t,ll limit)
{
    if(!limit || u==t)
        return limit;
    ll Flow=0,f;
    for(int i=cur[u];i!=-1;i=nx[i])
    {
        cur[u]=i;
        int v=to[i];
        if(dep[v]==dep[u]+1 && (f=dfs(v,t,min(limit,flow[i]))))
        {
            Flow+=f;
            limit-=f;
            flow[i]-=f;
            flow[i^1]+=f;
            if(!limit)
                break;
        }
    }
    return Flow;
}
void Dinic(int S,int T)
{
    while(bfs(S,T))
        maxflow+=dfs(S,T,inf);
}
int n,m,k;
int field[MAXN];
int main()
{
    freopen("work.in","r",stdin);
    freopen("work.out","w",stdout);
    memset(head,-1,sizeof head);
    int S=++tot;
    int T=++tot;
    n=read(),m=read(),k=read();
    ll ans=0;
    for(int i=1;i<=n;++i)
    {
        field[i]=++tot;
        ll a=read();
        ins(S,field[i],a);
        ans+=a;
    }
    for(int i=1;i<=n;++i)
    {
        ll b=read();
        ins(field[i],T,b);
        ans+=b;
    }
    while(m--)
    {
        int i=read(),j=read();
        ll w=read();
        ins(field[i],field[j],w);
        ins(field[j],field[i],w);
    }
    while(k--)
    {
        int t=read(),a=read();
        ll b=read();
        ans+=b;
        int np=++tot;
        if(a==0)
        {
            ins(S,np,b);
            for(int i=1;i<=t;++i)
            {
                int x=read();
                ins(np,field[x],inf);
            }
        }
        else
        {
            ins(np,T,b);
            for(int i=1;i<=t;++i)
            {
                int x=read();
                ins(field[x],np,inf);
            }
        }
    }
    Dinic(S,T);
    ans-=maxflow;
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/jklover/p/10659332.html

时间: 2024-10-12 16:45:57

bzoj 4177 Mike的农场的相关文章

bzoj4177: Mike的农场

类似于最大权闭合图的思想. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define clr(x,c) memset(x,c,sizeof(x)) #define op() pt=edges;clr(head,0) int rea

【BZOJ4177】Mike的农场 最小割

[BZOJ4177]Mike的农场 Description Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中第i个牲畜围栏中的动物长大后,每只牛可以卖a[i]元,每只羊可以卖b[i]元,为了防止牛羊之间相互影响,Mike找到了m条规律,每条规律给出一个三元组(i, j, k)表示如果第i个围栏和第j个围栏养的是不同的动物,那么Mike就需要花费k的代价请人帮忙处理牛羊之间的影响.不过同时Mike也发现k条

Mike的农场 (BZOJ 4177)

题目大意: 给N个东西分AB类,分到A类和B类分别得到相应的钱记为A[i],B[i],然后有一些冲突关系<x,y,z>,如果物品x,y不同类需要付出z的钱.还有一些外快<S,x,y>,当某个集合里的元素都是x类的时候得到y的钱. 求最大收益. 思路: 1.如果只考虑冲突关系,那么就是非常裸的最小割,显然这题应该在最小割的基础上加点东东. 然后集合附加权貌似是个比较经典的东西(虽然我也是做了这题才知道...),我这种蒟蒻肯定不能独立AC啦,于是愉快地看了题解.貌似和BZOJ3438是

【bzoj4177】Mike的农场 网络流最小割

题目描述 Mike有一个农场,这个农场n个牲畜围栏,现在他想在每个牲畜围栏中养一只动物,每只动物可以是牛或羊,并且每个牲畜围栏中的饲养条件都不同,其中第i个牲畜围栏中的动物长大后,每只牛可以卖a[i]元,每只羊可以卖b[i]元,为了防止牛羊之间相互影响,Mike找到了m条规律,每条规律给出一个三元组(i, j, k)表示如果第i个围栏和第j个围栏养的是不同的动物,那么Mike就需要花费k的代价请人帮忙处理牛羊之间的影响.不过同时Mike也发现k条特殊的规则(S, a, b),表示如果S中所有牲畜

bzoj:2018: [Usaco2009 Nov]农场技艺大赛

Description Input 第1行:10个空格分开的整数: N, a, b, c, d, e, f, g, h, M Output 第1行:满足总重量最轻,且用度之和最大的N头奶牛的总体重模M后的余数. Sample Input 2 0 1 5 55555555 0 1 0 55555555 55555555 Sample Output 51 HINT 样例说明:公式生成的体重和有用度分别为: 体重:5, 6, 9, 14, 21, 30 有用度:0, 1, 8, 27, 64, 125

bzoj4177:最小割

试着用证明文理分科那道题的方法去推,取st和单独两个点(简化问题),发现收取费用k可以在u和v中间连双向边,三种情况也还是分别对应:一是割掉与s相连的两条边,即都养羊,二是割掉与t相连的两条边,即都养羊,三是割掉s->i,j->i,j->t三条边图就不联通了,刚好对应养不同的牛.所以说多尝试是√的.happying 1.点的数量开始写成2*nWA 2.相同的变量名WA ------------------------------------------------------------

【个人整理】网络流

说明:S,表示超级原点,T表示超级汇点,<i,j,k(,l)>表示i到j建边,流量为k(,费用为l) bzoj4177 Mike的农场 题解:考虑割,养牛的收益为a[i],养羊b[i],对于每个位置<S,i,ai> <i,T,bi>分别表示养牛和养羊,对于两个互相影响的位置<i,j,ci>:做最小割可以满足前两个限制 :第三个限制,如果全养牛可以获得d,新建一个点x,考虑要求全养牛的位置为集合为s,<S,x,d> , <x,si,inf&g

[bzoj]3436 小K的农场

[题目描述] 小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:农场a比农场b至少多种植了c个单位的作物,农场a比农场b至多多种植了c个单位的作物,农场a与农场b种植的作物数一样多.但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合. [输入格式] farm.in 第一行包括两个整数n和m,分别表示农场数目和小K记忆中的信息数目. 接下来m

BZOJ 3436 小K的农场 查分约束系统 SPFA判负环

题目大意:农场中有一些土地,上面会长一些作物,现在给出一些约束条件,问有没有这种可能. 思路:裸的查分约束系统判负环.记住要跑最长路. CODE: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 using namespace std; int points,asks;